{"id":1324,"date":"2026-09-23T23:56:31","date_gmt":"2026-09-23T14:56:31","guid":{"rendered":"https:\/\/roundwide.com\/?p=1324"},"modified":"2026-09-24T23:16:01","modified_gmt":"2026-09-24T14:16:01","slug":"ef-core-in-memory-composite-key-join","status":"publish","type":"post","link":"https:\/\/roundwide.com\/ja\/ef-core-in-memory-composite-key-join\/","title":{"rendered":"EF Core\u3067\u30a4\u30f3\u30e1\u30e2\u30ea\u306e\u8907\u5408\u30ad\u30fc\u96c6\u5408\u3068DB\u30ec\u30b3\u30fc\u30c9\u3092\u7167\u5408\u3059\u308b"},"content":{"rendered":"\n<p>\u5916\u90e8API\u3084CSV\u304b\u3089\u53d6\u5f97\u3057\u305f\u30ad\u30fc\u306e\u4e00\u89a7\u3092\u4f7f\u3063\u3066\u3001\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304b\u3089\u8a72\u5f53\u30ec\u30b3\u30fc\u30c9\u3092\u53d6\u5f97\u3057\u305f\u3044\u3053\u3068\u304c\u3042\u308b\u3002\u5358\u4e00\u5217\u306e\u30ad\u30fc\u306a\u3089<code>Contains<\/code>\u3067\u66f8\u3051\u308b\u304c\u3001\u8907\u5408\u30ad\u30fc\u306b\u306a\u308b\u3068\u5c11\u3057\u5384\u4ecb\u3067\u3042\u308b\u3002<\/p>\n\n\n\n<p>\u305f\u3068\u3048\u3070\u3001DB\u5074\u306e<code>DbRecord<\/code>\u3068\u30e1\u30e2\u30ea\u4e0a\u306e<code>CompositeKey<\/code>\u3092<code>Key1<\/code>\u3001<code>Key2<\/code>\u3067\u7d50\u5408\u3059\u308b\u3082\u306e\u3068\u3059\u308b\u3002<\/p>\n\n\n\n<script type=\"text\/plain\" class=\"lang-csharp\">public sealed class DbRecord\n{\n    public int Key1 { get; set; }\n    public string Key2 { get; set; } = null!;\n    public string Payload { get; set; } = null!;\n}\npublic sealed record CompositeKey(int Key1, string Key2);<\/script>\n\n\n\n<p>\u7d20\u76f4\u306b\u66f8\u3051\u3070\u3001\u6b21\u306e\u3088\u3046\u306a<code>Join<\/code>\u306b\u306a\u308b\u3002<\/p>\n\n\n\n<script type=\"text\/plain\" class=\"lang-csharp\">var records = await db.Records\n    .Join(\n        keys,\n        record => new { record.Key1, record.Key2 },\n        key => new { key.Key1, key.Key2 },\n        (record, _) => record)\n    .AsNoTracking()\n    .ToListAsync(cancellationToken);<\/script>\n\n\n\n<p>\u3057\u304b\u3057\u3001<code>db.Records<\/code>\u306fSQL\u3078\u5909\u63db\u3055\u308c\u308b<code>IQueryable<\/code>\u3067\u3042\u308b\u306e\u306b\u5bfe\u3057\u3001<code>keys<\/code>\u306f\u30e1\u30e2\u30ea\u4e0a\u306e\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u96c6\u5408\u3067\u3042\u308b\u3002\u3053\u306e\u4e21\u8005\u3092\u8907\u5408\u30ad\u30fc\u3067\u7d50\u5408\u3059\u308b<code>Join<\/code>\u306fSQL\u3078\u5909\u63db\u3067\u304d\u305a\u3001\u5b9f\u884c\u6642\u306b\u4f8b\u5916\u3068\u306a\u308b\u3002<\/p>\n\n\n\n<p>\u5148\u306b<code>AsEnumerable<\/code>\u3092\u547c\u3079\u3070LINQ to Objects\u3068\u3057\u3066\u7d50\u5408\u3067\u304d\u308b\u304c\u3001\u305d\u306e\u305f\u3081\u306b\u306f\u7167\u5408\u524d\u306eDB\u30ec\u30b3\u30fc\u30c9\u3092\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u3078\u8aad\u307f\u8fbc\u307e\u306a\u3051\u308c\u3070\u306a\u3089\u306a\u3044\u3002\u305d\u308c\u3092\u907f\u3051\u308b\u306b\u306f\u3001\u30ad\u30fc\u96c6\u5408\u3092SQL\u3078\u6e21\u305b\u308b\u5f62\u5f0f\u306b\u5909\u63db\u3057\u3001\u7167\u5408\u3092DB\u5074\u3067\u5b9f\u884c\u3067\u304d\u308b\u3088\u3046\u306b\u3059\u308b\u5fc5\u8981\u304c\u3042\u308b\u3002<\/p>\n\n\n\n<p>\u3053\u306e\u8a18\u4e8b\u3067\u306f\u3001\u305d\u306e\u305f\u3081\u306b\u5b9f\u88c5\u3057\u305f\u6b21\u306e2\u65b9\u5f0f\u3092\u6bd4\u8f03\u3059\u308b\u3002<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30ad\u30fc\u96c6\u5408\u3092<code>WHERE<\/code>\u6761\u4ef6\u3078\u5c55\u958b\u3059\u308b<code>CompositeKeyPredicateBuilder<\/code><\/li>\n\n\n\n<li>\u30ad\u30fc\u96c6\u5408\u3092JSON\u3067\u6e21\u3057\u3001SQL Server\u306e<code>OPENJSON<\/code>\u3067\u884c\u30bb\u30c3\u30c8\u306b\u5c55\u958b\u3059\u308b<code>OpenJsonQueryBuilder<\/code><\/li>\n<\/ul>\n\n\n\n<p>\u3053\u306e\u8a18\u4e8b\u3067\u306f\u30b3\u30fc\u30c9\u306e\u8981\u70b9\u3060\u3051\u3092\u629c\u7c8b\u3057\u3066\u3044\u308b\u3002\u5b8c\u5168\u306a\u5b9f\u88c5\u3068\u30d9\u30f3\u30c1\u30de\u30fc\u30af\u4e00\u5f0f\u306f<a href=\"https:\/\/github.com\/fujieda\/EfCoreJoinBenchmark\">GitHub\u30ea\u30dd\u30b8\u30c8\u30ea<\/a>\u3067\u516c\u958b\u3057\u3066\u3044\u308b\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u5f0f\u6728\u3067<code>WHERE<\/code>\u6761\u4ef6\u3078\u5c55\u958b\u3059\u308b<\/h2>\n\n\n\n<p>1\u3064\u76ee\u306f\u3001\u5404\u30ad\u30fc\u5185\u306e\u8981\u7d20\u3092AND\u3067\u3001\u30ad\u30fc\u3054\u3068\u306e\u6761\u4ef6\u3092OR\u3067\u3064\u306a\u3044\u3060\u8ff0\u8a9e\u3092\u751f\u6210\u3059\u308b\u65b9\u6cd5\u3067\u3042\u308b\u30022\u4ef6\u306e\u30ad\u30fc\u3092\u6e21\u3057\u305f\u5834\u5408\u3001\u6b21\u306e\u3088\u3046\u306a\u6761\u4ef6\u3092\u751f\u6210\u3059\u308b\u3002<\/p>\n\n\n\n<script type=\"text\/plain\" class=\"lang-csharp\">record =>\n    (record.Key1 == 1 && record.Key2 == \"K00001\") ||\n    (record.Key1 == 2 && record.Key2 == \"K00002\")<\/script>\n\n\n\n<p>\u3053\u306e\u5f62\u306e\u5f0f\u306a\u3089\u3001EF Core\u306f\u901a\u5e38\u306e<code>Where<\/code>\u6761\u4ef6\u3068\u3057\u3066SQL\u3078\u5909\u63db\u3067\u304d\u308b\u3002\u547c\u3073\u51fa\u3057\u5074\u306f\u3001\u30a8\u30f3\u30c6\u30a3\u30c6\u30a3\u5074\u3068\u5165\u529b\u30ad\u30fc\u5074\u306e\u5bfe\u5fdc\u3059\u308b\u30d7\u30ed\u30d1\u30c6\u30a3\u3092\u6307\u5b9a\u3057\u3001\u751f\u6210\u3055\u308c\u305f\u8ff0\u8a9e\u3092\u6e21\u3059\u3060\u3051\u3067\u3042\u308b\u3002<\/p>\n\n\n\n<script type=\"text\/plain\" class=\"lang-csharp\">var builder = new CompositeKeyPredicateBuilder<DbRecord, CompositeKey>(\n    [nameof(DbRecord.Key1), nameof(DbRecord.Key2)],\n    [nameof(CompositeKey.Key1), nameof(CompositeKey.Key2)]);\nvar predicate = builder.Build(keys);\nvar records = await db.Records\n    .AsNoTracking()\n    .Where(predicate)\n    .ToListAsync(cancellationToken);<\/script>\n\n\n\n<p>\u30d3\u30eb\u30c0\u30fc\u306e\u4e2d\u5fc3\u90e8\u5206\u3067\u306f\u3001\u30ad\u30fc1\u4ef6\u3054\u3068\u306e\u6bd4\u8f03\u5f0f\u3092\u4f5c\u308a\u3001\u305d\u308c\u3089\u30921\u3064\u306e<code>Expression&lt;Func&lt;TEntity, bool&gt;&gt;<\/code>\u3078\u307e\u3068\u3081\u3066\u3044\u308b\u3002<\/p>\n\n\n\n<script type=\"text\/plain\" class=\"lang-csharp\">public Expression<Func<TEntity, bool>> Build(IEnumerable<TKey> keys)\n{\n    ArgumentNullException.ThrowIfNull(keys);\n    var entityParameter = Expression.Parameter(typeof(TEntity), \"entity\");\n    var matches = new List<Expression>();\n    foreach (var key in keys)\n    {\n        ArgumentNullException.ThrowIfNull(key);\n        var comparisons = new Expression[_entityProperties.Length];\n        for (var index = 0; index < _entityProperties.Length; index++)\n        {\n            var property = _entityProperties[index];\n            var propertyAccess = Expression.Property(entityParameter, property);\n            var constant = Expression.Constant(_keyGetters[index](key), property.PropertyType);\n            comparisons[index] = Expression.Equal(propertyAccess, constant);\n        }\n        matches.Add(BuildBalancedAnd(comparisons, 0, comparisons.Length));\n    }\n    var predicate = BuildBalancedOr(matches, 0, matches.Count)\n        ?? Expression.Constant(false);\n    return Expression.Lambda<Func<TEntity, bool>>(predicate, entityParameter);\n}<\/script>\n\n\n\n<p>\u30ad\u30fc\u96c6\u5408\u304c\u7a7a\u306e\u5834\u5408\u306f\u5e38\u306b<code>false<\/code>\u3068\u306a\u308b\u8ff0\u8a9e\u3092\u751f\u6210\u3059\u308b\u305f\u3081\u3001\u547c\u3073\u51fa\u3057\u5074\u306b\u7279\u5225\u306a\u5206\u5c90\u3092\u8a2d\u3051\u308b\u5fc5\u8981\u306f\u306a\u3044\u3002\u307e\u305f\u3001\u30d7\u30ed\u30d1\u30c6\u30a3\u6570\u306e\u4e0d\u4e00\u81f4\u3001\u5b58\u5728\u3057\u306a\u3044\u30d7\u30ed\u30d1\u30c6\u30a3\u540d\u3001\u578b\u306e\u4e0d\u4e00\u81f4\u3068\u3044\u3063\u305f\u8a2d\u5b9a\u8aa4\u308a\u306f\u3001\u30d3\u30eb\u30c0\u30fc\u306e\u69cb\u7bc9\u6642\u306b\u4f8b\u5916\u3068\u3057\u3066\u691c\u51fa\u3059\u308b\u3002<\/p>\n\n\n\n<p>\u3053\u306e\u65b9\u5f0f\u306fSQL Server\u56fa\u6709\u306e\u69cb\u6587\u3092\u4f7f\u308f\u306a\u3044\u3002\u65e2\u5b58\u306eLINQ\u3078\u7d44\u307f\u8fbc\u307f\u3084\u3059\u3044\u4e00\u65b9\u3001\u30ad\u30fc\u6570\u306b\u6bd4\u4f8b\u3057\u3066\u5f0f\u3068SQL\u304c\u5927\u304d\u304f\u306a\u308a\u3001\u5f0f\u306e\u751f\u6210\u3001SQL\u3078\u306e\u5909\u63db\u3001\u30e1\u30e2\u30ea\u5272\u308a\u5f53\u3066\u306e\u30b3\u30b9\u30c8\u3082\u5897\u3048\u308b\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u30ad\u30fc\u96c6\u5408\u3092JSON\u3067\u6e21\u3057\u3001<code>OPENJSON<\/code>\u3067\u5c55\u958b\u3059\u308b<\/h2>\n\n\n\n<p>2\u3064\u76ee\u306f\u3001\u30ad\u30fc\u96c6\u5408\u3092JSON\u6587\u5b57\u5217\u306b\u3057\u30661\u3064\u306eSQL\u30d1\u30e9\u30e1\u30fc\u30bf\u3067\u6e21\u3059\u65b9\u6cd5\u3067\u3042\u308b\u3002SQL Server\u5074\u3067\u306f<code>OPENJSON<\/code>\u306b\u3088\u3063\u3066JSON\u3092\u884c\u30bb\u30c3\u30c8\u306b\u5c55\u958b\u3057\u3001\u5143\u306e\u30c6\u30fc\u30d6\u30eb\u3068JOIN\u3059\u308b\u3002<\/p>\n\n\n\n<p>\u751f\u6210\u3055\u308c\u308bSQL\u306f\u6b21\u306e\u3088\u3046\u306b\u306a\u308b\u3002<\/p>\n\n\n\n<script type=\"text\/plain\" class=\"lang-sql\">SELECT r.[Key1], r.[Key2], r.[Payload]\nFROM [dbo].[DbRecords] AS r\nINNER JOIN OPENJSON(@json)\nWITH (\n    [Key1] int '$.Key1',\n    [Key2] varchar(50) '$.Key2'\n) AS inputKeys\n    ON r.[Key1] = inputKeys.[Key1]\n    AND r.[Key2] = inputKeys.[Key2]<\/script>\n\n\n\n<p>\u547c\u3073\u51fa\u3057\u65b9\u306f\u5f0f\u6728\u65b9\u5f0f\u3068\u307b\u307c\u540c\u3058\u3067\u3042\u308b\u3002<\/p>\n\n\n\n<script type=\"text\/plain\" class=\"lang-csharp\">var builder = new OpenJsonQueryBuilder<DbRecord, CompositeKey>(\n    [nameof(DbRecord.Key1), nameof(DbRecord.Key2)],\n    [nameof(CompositeKey.Key1), nameof(CompositeKey.Key2)]);\nvar records = await builder\n    .Build(db.Records, keys)\n    .ToListAsync(cancellationToken);<\/script>\n\n\n\n<p><code>Build<\/code>\u306f\u30ad\u30fc\u96c6\u5408\u3092\u30b7\u30ea\u30a2\u30e9\u30a4\u30ba\u3057\u3001\u751f\u6210\u3057\u305fSQL\u3092<code>FromSqlRaw<\/code>\u3078\u6e21\u3059\u3002<\/p>\n\n\n\n<script type=\"text\/plain\" class=\"lang-csharp\">public IQueryable<TEntity> Build(\n    DbSet<TEntity> source,\n    IReadOnlyCollection<TKey> keys)\n{\n    ArgumentNullException.ThrowIfNull(source);\n    ArgumentNullException.ThrowIfNull(keys);\n    var shape = SqlShapes.GetOrAdd(\n        GetShapeKey(source.EntityType),\n        _ => CreateSql(source.EntityType));\n    var json = JsonSerializer.Serialize(keys);\n    var parameter = new SqlParameter(\"@json\", json);\n    return source.FromSqlRaw(shape, parameter).AsNoTracking();\n}<\/script>\n\n\n\n<p><code>OPENJSON<\/code>\u306e<code>WITH<\/code>\u53e5\u306b\u306f\u3001EF Core\u306e\u30e2\u30c7\u30eb\u304b\u3089\u53d6\u5f97\u3057\u305f\u5b9f\u969b\u306e\u30c6\u30fc\u30d6\u30eb\u540d\u3001\u5217\u540d\u3001SQL\u578b\u3092\u4f7f\u3046\u3002\u5bfe\u5fdc\u3059\u308b\u30d7\u30ed\u30d1\u30c6\u30a3\u304c\u30de\u30c3\u30d4\u30f3\u30b0\u3055\u308c\u3066\u3044\u306a\u3044\u3001\u5165\u529b\u30ad\u30fc\u306b\u30d7\u30ed\u30d1\u30c6\u30a3\u304c\u306a\u3044\u3001CLR\u578b\u304c\u4e00\u81f4\u3057\u306a\u3044\u3001\u3068\u3044\u3063\u305f\u8a2d\u5b9a\u8aa4\u308a\u306fSQL\u3092\u5b9f\u884c\u3059\u308b\u524d\u306b\u30d3\u30eb\u30c0\u30fc\u304c\u691c\u51fa\u3059\u308b\u3002<\/p>\n\n\n\n<p><code>OPENJSON<\/code>\u306e<code>WITH<\/code>\u53e5\u306b\u306f\u3001EF Core\u306e\u30e2\u30c7\u30eb\u304b\u3089\u53d6\u5f97\u3057\u305f\u5b9f\u969b\u306e\u30c6\u30fc\u30d6\u30eb\u540d\u3001\u5217\u540d\u3001SQL\u578b\u3092\u4f7f\u3046\u3002\u30a8\u30f3\u30c6\u30a3\u30c6\u30a3\u5074\u306e\u30d7\u30ed\u30d1\u30c6\u30a3\u304c\u5217\u306b\u30de\u30c3\u30d4\u30f3\u30b0\u3055\u308c\u3066\u3044\u306a\u3044\u3001\u5165\u529b\u30ad\u30fc\u5074\u306b\u30d7\u30ed\u30d1\u30c6\u30a3\u304c\u306a\u3044\u3001CLR\u578b\u304c\u4e00\u81f4\u3057\u306a\u3044\u3001\u3068\u3044\u3063\u305f\u8a2d\u5b9a\u8aa4\u308a\u306fSQL\u3092\u5b9f\u884c\u3059\u308b\u524d\u306b\u30d3\u30eb\u30c0\u30fc\u304c\u691c\u51fa\u3059\u308b\u3002<\/p>\n\n\n\n<p><code>CreateSql<\/code>\u306eSQL\u7d44\u307f\u7acb\u3066\u90e8\u5206\u3067\u306f\u3001\u691c\u8a3c\u6e08\u307f\u306e\u30d7\u30ed\u30d1\u30c6\u30a3\u304b\u3089<code>SELECT<\/code>\u5217\u3001<code>OPENJSON<\/code>\u306e\u5165\u529b\u5217\u3001JOIN\u6761\u4ef6\u3092\u305d\u308c\u305e\u308c\u751f\u6210\u3057\u30011\u3064\u306eSQL\u6587\u306b\u57cb\u3081\u8fbc\u3080\u3002<\/p>\n\n\n\n<script type=\"text\/plain\" class=\"lang-csharp\">var selectColumns = string.Join(\", \", entityType.GetProperties()\n    .Select(property => $\"r.{QuoteIdentifier(property.GetColumnName(storeObject))}\"));\nvar inputColumns = string.Join(\",\\n\", entityProperties.Zip(keyProperties).Select(pair =>\n    $\"                    {QuoteIdentifier(pair.Second.Name)} {GetSqlType(pair.First, storeObject)} '$.{pair.Second.Name}'\"));\nvar joinConditions = string.Join(\"\\n                    AND \", entityProperties.Zip(keyProperties).Select(pair =>\n    $\"r.{QuoteIdentifier(pair.First.GetColumnName(storeObject))} = inputKeys.{QuoteIdentifier(pair.Second.Name)}\"));\nreturn $\"\"\"\n    SELECT {selectColumns}\n    FROM {QuoteIdentifier(entityType.GetSchema() ?? \"dbo\")}.{QuoteIdentifier(tableName)} AS r\n    INNER JOIN OPENJSON(@json)\n    WITH (\n    {inputColumns}\n    ) AS inputKeys\n        ON {joinConditions}\n    \"\"\";<\/script>\n\n\n\n<p>SQL\u306e\u5f62\u72b6\u306f\u30ad\u30fc\u6570\u306b\u304b\u304b\u308f\u3089\u305a\u4e00\u5b9a\u3067\u3042\u308a\u3001\u6e21\u3059\u30d1\u30e9\u30e1\u30fc\u30bf\u3082JSON\u6587\u5b57\u5217\u306e1\u3064\u3060\u3051\u3067\u3042\u308b\u3002\u305f\u3060\u3057\u3001SQL Server\u56fa\u6709\u306e<code>OPENJSON<\/code>\u3068\u751fSQL\u306b\u4f9d\u5b58\u3059\u308b\u305f\u3081\u3001\u4ed6\u306eDB\u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u3078\u305d\u306e\u307e\u307e\u79fb\u690d\u306f\u3067\u304d\u306a\u3044\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u30d9\u30f3\u30c1\u30de\u30fc\u30af<\/h2>\n\n\n\n<p>2\u65b9\u5f0f\u3092\u6b21\u306e\u74b0\u5883\u3067\u6e2c\u5b9a\u3057\u305f\u3002<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>.NET 10 \/ EF Core 10.0.0<\/li>\n\n\n\n<li>SQL Server 2022<\/li>\n\n\n\n<li>BenchmarkDotNet 0.15.6<\/li>\n\n\n\n<li>\u8907\u5408\u30ad\u30fc\u306f<code>int<\/code>\u3068<code>varchar(50)<\/code><\/li>\n\n\n\n<li>\u30ad\u30fc\u6570\u306f100\u30011,000\u300110,000<\/li>\n<\/ul>\n\n\n\n<p>\u5404\u30d9\u30f3\u30c1\u30de\u30fc\u30af\u3067\u306f\u3001\u6307\u5b9a\u4ef6\u6570\u306e\u30ad\u30fc\u3068\u4e00\u81f4\u3059\u308b\u30ec\u30b3\u30fc\u30c9\u3092DB\u306b\u7528\u610f\u3057\u3001\u30af\u30a8\u30ea\u3092\u5b9f\u884c\u3057\u3066\u53d6\u5f97\u4ef6\u6570\u3092\u8fd4\u3057\u3066\u3044\u308b\u3002\u3064\u307e\u308a\u3001\u8ff0\u8a9e\u3084SQL\u306e\u751f\u6210\u3060\u3051\u3067\u306a\u304f\u3001SQL Server\u3067\u306e\u7167\u5408\u3068\u7d50\u679c\u306e\u8aad\u307f\u8fbc\u307f\u307e\u3067\u304c\u6e2c\u5b9a\u5bfe\u8c61\u3067\u3042\u308b\u3002<\/p>\n\n\n\n<script type=\"text\/plain\" class=\"lang-csharp\">[Params(100, 1_000, 10_000)]\npublic int KeyCount { get; set; }\n[Benchmark(Baseline = true)]\npublic int ExpressionTree() =>\n    JoinQueries.ExecuteExpressionTreeAsync(_db, _keys)\n        .GetAwaiter().GetResult().Count;\n[Benchmark]\npublic int OpenJson() =>\n    JoinQueries.ExecuteOpenJsonAsync(_db, _keys)\n        .GetAwaiter().GetResult().Count;<\/script>\n\n\n\n<p>\u7d50\u679c\u306f\u6b21\u306e\u3068\u304a\u308a\u3067\u3042\u308b\u3002<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th class=\"has-text-align-right\" data-align=\"right\">\u30ad\u30fc\u6570<\/th><th class=\"has-text-align-right\" data-align=\"right\">\u5f0f\u6728<\/th><th class=\"has-text-align-right\" data-align=\"right\"><code>OPENJSON<\/code><\/th><th class=\"has-text-align-right\" data-align=\"right\">\u5f0f\u6728\u306e\u30e1\u30e2\u30ea\u5272\u5f53<\/th><th class=\"has-text-align-right\" data-align=\"right\"><code>OPENJSON<\/code>\u306e\u30e1\u30e2\u30ea\u5272\u5f53<\/th><\/tr><\/thead><tbody><tr><td class=\"has-text-align-right\" data-align=\"right\">100<\/td><td class=\"has-text-align-right\" data-align=\"right\">1.953 ms<\/td><td class=\"has-text-align-right\" data-align=\"right\">1.520 ms<\/td><td class=\"has-text-align-right\" data-align=\"right\">116.2 KB<\/td><td class=\"has-text-align-right\" data-align=\"right\">57.43 KB<\/td><\/tr><tr><td class=\"has-text-align-right\" data-align=\"right\">1,000<\/td><td class=\"has-text-align-right\" data-align=\"right\">6.018 ms<\/td><td class=\"has-text-align-right\" data-align=\"right\">4.074 ms<\/td><td class=\"has-text-align-right\" data-align=\"right\">1,086.5 KB<\/td><td class=\"has-text-align-right\" data-align=\"right\">431.79 KB<\/td><\/tr><tr><td class=\"has-text-align-right\" data-align=\"right\">10,000<\/td><td class=\"has-text-align-right\" data-align=\"right\">80.096 ms<\/td><td class=\"has-text-align-right\" data-align=\"right\">49.037 ms<\/td><td class=\"has-text-align-right\" data-align=\"right\">11,006.13 KB<\/td><td class=\"has-text-align-right\" data-align=\"right\">4,310.55 KB<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>100\u4ef6\u3067\u306f\u5dee\u306f0.433 ms\u3060\u304c\u300110,000\u4ef6\u3067\u306f31.059 ms\u307e\u3067\u5e83\u304c\u3063\u305f\u3002<code>OPENJSON<\/code>\u306e\u5b9f\u884c\u6642\u9593\u306f\u5f0f\u6728\u65b9\u5f0f\u306e\u7d0461%\u3001\u30e1\u30e2\u30ea\u5272\u308a\u5f53\u3066\u91cf\u306f\u7d0439%\u3067\u3042\u308b\u3002\u30ad\u30fc\u6570\u304c\u5897\u3048\u308b\u307b\u3069\u3001\u6761\u4ef6\u5f0f\u3092\u5c55\u958b\u3057\u306a\u3044\u3053\u3068\u306e\u52b9\u679c\u304c\u8868\u308c\u3066\u3044\u308b\u3002<\/p>\n\n\n\n<p>\u3082\u3061\u308d\u3093\u3001\u3053\u306e\u6570\u5024\u306f\u4eca\u56de\u4f7f\u7528\u3057\u305f\u30c7\u30fc\u30bf\u578b\u3001\u53d6\u5f97\u4ef6\u6570\u3001SQL Server\u306e\u8a2d\u5b9a\u3001\u304a\u3088\u3073\u5b9f\u884c\u74b0\u5883\u306b\u57fa\u3065\u304f\u7d50\u679c\u3067\u3042\u308b\u3002\u5b9f\u969b\u306e\u6027\u80fd\u306f\u30c6\u30fc\u30d6\u30eb\u306e\u5927\u304d\u3055\u3001\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3001\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u3001\u53d6\u5f97\u3059\u308b\u5217\u6570\u3084\u884c\u6570\u306b\u3082\u5de6\u53f3\u3055\u308c\u308b\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u3069\u3061\u3089\u3092\u4f7f\u3046\u304b<\/h2>\n\n\n\n<p>\u5224\u65ad\u57fa\u6e96\u306f\u3001\u30ad\u30fc\u6570\u3068\u3001DB\u56fa\u6709\u306e\u5b9f\u88c5\u3092\u8a31\u5bb9\u3067\u304d\u308b\u304b\u3069\u3046\u304b\u3067\u3042\u308b\u3002<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>\u6761\u4ef6<\/th><th>\u9078\u3073\u3084\u3059\u3044\u65b9\u5f0f<\/th><\/tr><\/thead><tbody><tr><td>SQL Server\u4ee5\u5916\u3067\u3082\u4f7f\u3044\u305f\u3044<\/td><td>\u5f0f\u6728<\/td><\/tr><tr><td>\u901a\u5e38\u306eLINQ\u3068\u3057\u3066\u7d44\u307f\u7acb\u3066\u305f\u3044<\/td><td>\u5f0f\u6728<\/td><\/tr><tr><td>\u30ad\u30fc\u96c6\u5408\u304c\u5c0f\u3055\u3044<\/td><td>\u5f0f\u6728<\/td><\/tr><tr><td>SQL Server\u306b\u56fa\u5b9a\u3067\u304d\u308b<\/td><td><code>OPENJSON<\/code><\/td><\/tr><tr><td>\u5927\u304d\u306a\u30ad\u30fc\u96c6\u5408\u3092\u983b\u7e41\u306b\u7167\u5408\u3059\u308b<\/td><td><code>OPENJSON<\/code><\/td><\/tr><tr><td>SQL\u3068\u5272\u308a\u5f53\u3066\u306e\u5897\u52a0\u3092\u6291\u3048\u305f\u3044<\/td><td><code>OPENJSON<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>\u5c0f\u3055\u306a\u30ad\u30fc\u96c6\u5408\u306a\u3089\u3001\u5f0f\u6728\u65b9\u5f0f\u306f\u5358\u7d14\u3067\u6271\u3044\u3084\u3059\u304f\u3001DB\u56fa\u6709\u306e\u30b3\u30fc\u30c9\u3082\u4e0d\u8981\u3067\u3042\u308b\u3002\u30ad\u30fc\u96c6\u5408\u304c\u5927\u304d\u3044\u5834\u5408\u3001\u5229\u7528\u3059\u308bDB\u3092SQL Server\u306b\u9650\u5b9a\u3067\u304d\u308b\u306a\u3089\u3001SQL\u306e\u5f62\u72b6\u3092\u4e00\u5b9a\u306b\u4fdd\u3066\u308b<code>OPENJSON<\/code>\u65b9\u5f0f\u304c\u6709\u529b\u3067\u3042\u308b\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u5b9f\u884c\u65b9\u6cd5<\/h2>\n\n\n\n<p>\u30ea\u30dd\u30b8\u30c8\u30ea\u306eDocker Compose\u69cb\u6210\u3092\u4f7f\u3048\u3070\u3001SQL Server\u3092\u8d77\u52d5\u3067\u304d\u308b\u3002<\/p>\n\n\n\n<script type=\"text\/plain\" class=\"lang-powershell\">docker compose up -d<\/script>\n\n\n\n<p>\u63a5\u7d9a\u6587\u5b57\u5217\u3092\u8a2d\u5b9a\u3057\u3001Release\u69cb\u6210\u3067\u30d9\u30f3\u30c1\u30de\u30fc\u30af\u3092\u5b9f\u884c\u3059\u308b\u3002<\/p>\n\n\n\n<script type=\"text\/plain\" class=\"lang-powershell\">$env:EF_JOIN_CONNECTION_STRING = \"Server=localhost,14333;Database=EfCoreJoinBenchmark;User Id=sa;Password=Your_strong_password123;TrustServerCertificate=True;\"\ndotnet run --project .\\EfCoreJoinBenchmark.Benchmarks -c Release<\/script>\n\n\n\n<h2 class=\"wp-block-heading\">\u307e\u3068\u3081<\/h2>\n\n\n\n<p>\u30a4\u30f3\u30e1\u30e2\u30ea\u306e\u8907\u5408\u30ad\u30fc\u96c6\u5408\u3092<code>IQueryable<\/code>\u3078\u76f4\u63a5<code>Join<\/code>\u3059\u308b\u3068\u3001EF Core\u306f\u305d\u306e\u30af\u30a8\u30ea\u3092SQL\u3078\u5909\u63db\u3067\u304d\u306a\u3044\u3002DB\u5074\u3067\u7167\u5408\u3059\u308b\u306b\u306f\u3001\u30ad\u30fc\u96c6\u5408\u3092SQL\u3078\u6e21\u305b\u308b\u5f62\u5f0f\u306b\u5909\u63db\u3059\u308b\u5fc5\u8981\u304c\u3042\u308b\u3002<\/p>\n\n\n\n<p>\u5f0f\u6728\u65b9\u5f0f\u306f\u3001\u30ad\u30fc\u3092AND\u3068OR\u304b\u3089\u306a\u308b<code>Where<\/code>\u6761\u4ef6\u3078\u5909\u63db\u3059\u308b\u3002LINQ\u3068\u3057\u3066\u6271\u3044\u3084\u3059\u304fDB\u56fa\u6709\u306e\u6a5f\u80fd\u3092\u907f\u3051\u3089\u308c\u308b\u304c\u3001\u30ad\u30fc\u6570\u3068\u3068\u3082\u306b\u5f0f\u3068SQL\u304c\u5927\u304d\u304f\u306a\u308b\u3002<\/p>\n\n\n\n<p><code>OPENJSON<\/code>\u65b9\u5f0f\u306f\u3001\u30ad\u30fc\u96c6\u5408\u30921\u3064\u306eJSON\u30d1\u30e9\u30e1\u30fc\u30bf\u3067\u9001\u308a\u3001SQL Server\u4e0a\u3067\u884c\u30bb\u30c3\u30c8\u306b\u5c55\u958b\u3059\u308b\u3002SQL Server\u306b\u4f9d\u5b58\u3059\u308b\u304c\u3001\u4eca\u56de\u306e\u6e2c\u5b9a\u3067\u306f\u30ad\u30fc\u6570\u304c\u591a\u3044\u307b\u3069\u5b9f\u884c\u6642\u9593\u3068\u30e1\u30e2\u30ea\u5272\u308a\u5f53\u3066\u306e\u4e21\u65b9\u3067\u6709\u5229\u3067\u3042\u3063\u305f\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u5916\u90e8API\u3084CSV\u304b\u3089\u53d6\u5f97\u3057\u305f\u30ad\u30fc\u306e\u4e00\u89a7\u3092\u4f7f\u3063\u3066\u3001\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304b\u3089\u8a72\u5f53\u30ec\u30b3\u30fc\u30c9\u3092\u53d6\u5f97\u3057\u305f\u3044\u3053\u3068\u304c\u3042\u308b\u3002\u5358\u4e00\u5217\u306e\u30ad\u30fc\u306a\u3089Contains\u3067\u66f8\u3051\u308b\u304c\u3001\u8907\u5408\u30ad\u30fc\u306b\u306a\u308b\u3068\u5c11\u3057\u5384\u4ecb\u3067\u3042\u308b\u3002 \u305f\u3068\u3048\u3070\u3001DB\u5074\u306eDbRecord\u3068\u30e1\u30e2 &hellip; <a href=\"https:\/\/roundwide.com\/ja\/ef-core-in-memory-composite-key-join\/\" class=\"more-link\"><span class=\"screen-reader-text\">\"EF Core\u3067\u30a4\u30f3\u30e1\u30e2\u30ea\u306e\u8907\u5408\u30ad\u30fc\u96c6\u5408\u3068DB\u30ec\u30b3\u30fc\u30c9\u3092\u7167\u5408\u3059\u308b\" \u306e<\/span>\u7d9a\u304d\u3092\u8aad\u3080<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_locale":"ja","_original_post":"https:\/\/roundwide.com\/?p=1324","footnotes":""},"categories":[1],"tags":[],"class_list":["post-1324","post","type-post","status-publish","format-standard","hentry","category-1","ja"],"_links":{"self":[{"href":"https:\/\/roundwide.com\/wp-json\/wp\/v2\/posts\/1324","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/roundwide.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/roundwide.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/roundwide.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/roundwide.com\/wp-json\/wp\/v2\/comments?post=1324"}],"version-history":[{"count":8,"href":"https:\/\/roundwide.com\/wp-json\/wp\/v2\/posts\/1324\/revisions"}],"predecessor-version":[{"id":1341,"href":"https:\/\/roundwide.com\/wp-json\/wp\/v2\/posts\/1324\/revisions\/1341"}],"wp:attachment":[{"href":"https:\/\/roundwide.com\/wp-json\/wp\/v2\/media?parent=1324"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/roundwide.com\/wp-json\/wp\/v2\/categories?post=1324"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/roundwide.com\/wp-json\/wp\/v2\/tags?post=1324"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}