2017-09-07 9 views
1

efクエリを最適化しようとするときに問題があります。私は生成されたSQLでもエンティティ構文にマッピングすることを言及していないにもかかわらず、何が変わるのか分かりません。どのような最適化のヒントにも大変感謝しています。 EFの問合せ:PostGresqlのEFから生成されたクエリで最適でないカウント

var data = Context.Premise.Where(p => p.TransportManager != null); 
var query = from premise in data 
         join psi in Context.PremiseSeriousInfringement on premise.Id equals psi.PremiseId 
         group psi by psi.Premise into bp 
         let types = from type in bp 
            select type.SeriousInfringement.SeriousInfringementCode.SeriousInfringementType.Value 
         let premise = bp.Key 
         let NNInfringementCount = types.Count(t => t == "NN") 
         let BPNInfringementCount = types.Count(t => t == "BPN") 
         let PNInfringementCount = types.Count(t => t == "PN") 
         select new 
         { 
          NNInfringementCount, 
          BPNInfringementCount, 
          PNInfringementCount, 
          premise.Id, 
          premise.Type, 
          premise.Status, 
          premise.CreationDate, 
          premise.BusinessCaseNumber, 

          FirstNames = premise.TransportManager.FirstNames, 
          FamilyName = premise.TransportManager.FamilyName, 
          CertificateNumber = premise.TransportManager.CertificateNumber, 

          Types = types 
         }; 
query = query.OrderBy(filter.sortField + " " + filter.sortOrder) 
      .Skip((filter.pageIndex - 1) * filter.pageSize) 
      .Take(filter.pageSize); 

これは、それが生成するクエリである[私はそれがより読みやすくなりましたEDIT]:

SELECT "Project8"."UndertakingId", "Project8"."TransportManagerId", "Project8"."CancelReasons", "Project8"."WarningDate", "Project8"."WarningDeliveryDate", "Project8"."FinishDate", "Project8"."InternalProceeding", "Project8"."AuthorityId", "Project8"."PenaltyImposed", "Project8"."PenaltyDescription", "Project8"."PenaltyType", "Project8"."isSendToEpuap", "Project8"."ModificationDate", "Project8"."CreatedByAppUserId", "Project8"."LastModifiedByAppUserId", "Project8"."Id1" AS "Id", "Project8"."Id" AS "Id1", "Project8"."C2" AS "C1", "Project8"."C3" AS "C2", "Project8"."C4" AS "C3", "Project8"."Type", "Project8"."Status", "Project8"."CreationDate", "Project8"."BusinessCaseNumber", "Project8"."FirstNames", "Project8"."FamilyName", "Project8"."CertificateNumber", "Project8"."C1" AS "C4", "Project8"."Value" FROM (
SELECT "Join14"."Id", "Join14"."UndertakingId", "Join14"."TransportManagerId", "Join14"."Type", "Join14"."Status", "Join14"."CancelReasons", "Join14"."WarningDate", "Join14"."WarningDeliveryDate", "Join14"."FinishDate", "Join14"."InternalProceeding", "Join14"."AuthorityId", "Join14"."PenaltyImposed", "Join14"."PenaltyDescription", "Join14"."BusinessCaseNumber", "Join14"."PenaltyType", "Join14"."isSendToEpuap", "Join14"."CreationDate", "Join14"."ModificationDate", "Join14"."CreatedByAppUserId", "Join14"."LastModifiedByAppUserId", "Join14"."Id_Alias12" AS "Id1", "Join14"."CertificateNumber", "Join14"."FirstNames", "Join14"."FamilyName", "Join18"."Value", CASE WHEN ("Join18"."SeriousInfringementId" IS NULL) THEN (CAST (NULL AS int4)) ELSE (1) END AS "C1", "Join14"."C1" AS "C2", "Join14"."C2" AS "C3", "Join14"."C3" AS "C4" FROM (
SELECT "Project7"."Id", "Project7"."UndertakingId", "Project7"."TransportManagerId", "Project7"."Type", "Project7"."Status", "Project7"."CancelReasons", "Project7"."WarningDate", "Project7"."WarningDeliveryDate", "Project7"."FinishDate", "Project7"."InternalProceeding", "Project7"."AuthorityId", "Project7"."PenaltyImposed", "Project7"."PenaltyDescription", "Project7"."BusinessCaseNumber", "Project7"."PenaltyType", "Project7"."isSendToEpuap", "Project7"."CreationDate", "Project7"."ModificationDate", "Project7"."CreatedByAppUserId", "Project7"."LastModifiedByAppUserId", "Extent18"."Id" AS "Id_Alias12", "Extent18"."CertificateNumber", "Extent18"."FirstNames", "Extent18"."FamilyName", "Project7"."C1", "Project7"."C2", "Project7"."C3" FROM (
SELECT "Project5"."Id", "Project5"."UndertakingId", "Project5"."TransportManagerId", "Project5"."Type", "Project5"."Status", "Project5"."CancelReasons", "Project5"."WarningDate", "Project5"."WarningDeliveryDate", "Project5"."FinishDate", "Project5"."InternalProceeding", "Project5"."AuthorityId", "Project5"."PenaltyImposed", "Project5"."PenaltyDescription", "Project5"."BusinessCaseNumber", "Project5"."PenaltyType", "Project5"."isSendToEpuap", "Project5"."CreationDate", "Project5"."ModificationDate", "Project5"."CreatedByAppUserId", "Project5"."LastModifiedByAppUserId", "Project5"."C1", "Project5"."C2", (
SELECT CAST (count(1) AS int4) AS "A1" FROM (
SELECT "Join12"."SeriousInfringementId", "Join12"."Id_Alias10" AS "Id", "Join12"."SeriousInfringementCodeId", "Join12"."Id_Alias11" AS "Id1", "Join12"."SeriousInfringementTypeId", "Extent17"."Id" AS "Id2", "Extent17"."Value" FROM (
SELECT "Extent16"."SeriousInfringementTypeId", "Extent13"."Id", "Extent14"."SeriousInfringementId", "Extent15"."Id" AS "Id_Alias10", "Extent15"."SeriousInfringementCodeId", "Extent16"."Id" AS "Id_Alias11" FROM "dbo"."Premise" AS "Extent13" 
INNER JOIN "dbo"."PremiseSeriousInfringement" AS "Extent14" ON "Extent13"."Id" = "Extent14"."PremiseId" 
INNER JOIN "dbo"."SeriousInfringement" AS "Extent15" ON "Extent14"."SeriousInfringementId" = "Extent15"."Id" 
INNER JOIN "dbo"."SeriousInfringementCode" AS "Extent16" ON "Extent15"."SeriousInfringementCodeId" = "Extent16"."Id" WHERE "Extent13"."TransportManagerId" IS NOT NULL) AS "Join12" 
INNER JOIN "dbo"."DictionaryValue" AS "Extent17" ON "Join12"."SeriousInfringementTypeId" = "Extent17"."Id" WHERE ("Project5"."Id" = "Join12"."Id" OR TRUE = FALSE) AND E'PN' = "Extent17"."Value") AS "Project6") AS "C3" FROM (
SELECT "Project3"."Id", "Project3"."UndertakingId", "Project3"."TransportManagerId", "Project3"."Type", "Project3"."Status", "Project3"."CancelReasons", "Project3"."WarningDate", "Project3"."WarningDeliveryDate", "Project3"."FinishDate", "Project3"."InternalProceeding", "Project3"."AuthorityId", "Project3"."PenaltyImposed", "Project3"."PenaltyDescription", "Project3"."BusinessCaseNumber", "Project3"."PenaltyType", "Project3"."isSendToEpuap", "Project3"."CreationDate", "Project3"."ModificationDate", "Project3"."CreatedByAppUserId", "Project3"."LastModifiedByAppUserId", "Project3"."C1", (
SELECT CAST (count(1) AS int4) AS "A1" FROM (
SELECT "Join8"."SeriousInfringementId", "Join8"."Id_Alias7" AS "Id", "Join8"."SeriousInfringementCodeId", "Join8"."Id_Alias8" AS "Id1", "Join8"."SeriousInfringementTypeId", "Extent12"."Id" AS "Id2", "Extent12"."Value" FROM (
SELECT "Extent11"."SeriousInfringementTypeId", "Extent8"."Id", "Extent9"."SeriousInfringementId", "Extent10"."Id" AS "Id_Alias7", "Extent10"."SeriousInfringementCodeId", "Extent11"."Id" AS "Id_Alias8" FROM "dbo"."Premise" AS "Extent8" 
INNER JOIN "dbo"."PremiseSeriousInfringement" AS "Extent9" ON "Extent8"."Id" = "Extent9"."PremiseId" 
INNER JOIN "dbo"."SeriousInfringement" AS "Extent10" ON "Extent9"."SeriousInfringementId" = "Extent10"."Id" 
INNER JOIN "dbo"."SeriousInfringementCode" AS "Extent11" ON "Extent10"."SeriousInfringementCodeId" = "Extent11"."Id" WHERE "Extent8"."TransportManagerId" IS NOT NULL) AS "Join8" 
INNER JOIN "dbo"."DictionaryValue" AS "Extent12" ON "Join8"."SeriousInfringementTypeId" = "Extent12"."Id" WHERE ("Project3"."Id" = "Join8"."Id" OR TRUE = FALSE) AND E'BPN' = "Extent12"."Value") AS "Project4") AS "C2" FROM (
SELECT "Alias2"."Id", "Alias2"."UndertakingId", "Alias2"."TransportManagerId", "Alias2"."Type", "Alias2"."Status", "Alias2"."CancelReasons", "Alias2"."WarningDate", "Alias2"."WarningDeliveryDate", "Alias2"."FinishDate", "Alias2"."InternalProceeding", "Alias2"."AuthorityId", "Alias2"."PenaltyImposed", "Alias2"."PenaltyDescription", "Alias2"."BusinessCaseNumber", "Alias2"."PenaltyType", "Alias2"."isSendToEpuap", "Alias2"."CreationDate", "Alias2"."ModificationDate", "Alias2"."CreatedByAppUserId", "Alias2"."LastModifiedByAppUserId", (
SELECT CAST (count(1) AS int4) AS "A1" FROM (
SELECT "Join4"."SeriousInfringementId", "Join4"."Id_Alias4" AS "Id", "Join4"."SeriousInfringementCodeId", "Join4"."Id_Alias5" AS "Id1", "Join4"."SeriousInfringementTypeId", "Extent7"."Id" AS "Id2", "Extent7"."Value" FROM (
SELECT "Extent6"."SeriousInfringementTypeId", "Extent3"."Id", "Extent4"."SeriousInfringementId", "Extent5"."Id" AS "Id_Alias4", "Extent5"."SeriousInfringementCodeId", "Extent6"."Id" AS "Id_Alias5" FROM "dbo"."Premise" AS "Extent3" 
INNER JOIN "dbo"."PremiseSeriousInfringement" AS "Extent4" ON "Extent3"."Id" = "Extent4"."PremiseId" 
INNER JOIN "dbo"."SeriousInfringement" AS "Extent5" ON "Extent4"."SeriousInfringementId" = "Extent5"."Id" 
INNER JOIN "dbo"."SeriousInfringementCode" AS "Extent6" ON "Extent5"."SeriousInfringementCodeId" = "Extent6"."Id" WHERE "Extent3"."TransportManagerId" IS NOT NULL) AS "Join4" 
INNER JOIN "dbo"."DictionaryValue" AS "Extent7" ON "Join4"."SeriousInfringementTypeId" = "Extent7"."Id" WHERE ("Alias2"."Id" = "Join4"."Id" OR TRUE = FALSE) AND E'NN' = "Extent7"."Value") AS "Project2") AS "C1" FROM (
SELECT DISTINCT "Extent1"."Id", "Extent1"."UndertakingId", "Extent1"."TransportManagerId", "Extent1"."Type", "Extent1"."Status", "Extent1"."CancelReasons", "Extent1"."WarningDate", "Extent1"."WarningDeliveryDate", "Extent1"."FinishDate", "Extent1"."InternalProceeding", "Extent1"."AuthorityId", "Extent1"."PenaltyImposed", "Extent1"."PenaltyDescription", "Extent1"."BusinessCaseNumber", "Extent1"."PenaltyType", "Extent1"."isSendToEpuap", "Extent1"."CreationDate", "Extent1"."ModificationDate", "Extent1"."CreatedByAppUserId", "Extent1"."LastModifiedByAppUserId" FROM "dbo"."Premise" AS "Extent1" 
INNER JOIN "dbo"."PremiseSeriousInfringement" AS "Extent2" ON "Extent1"."Id" = "Extent2"."PremiseId" AND "Extent2"."PremiseId" = "Extent1"."Id" WHERE "Extent1"."TransportManagerId" IS NOT NULL) AS "Alias2") AS "Project3") AS "Project5") AS "Project7" 
LEFT OUTER JOIN "dbo"."TransportManager" AS "Extent18" ON "Project7"."TransportManagerId" = "Extent18"."Id" ORDER BY "Project7"."Type" ASC OFFSET 0 LIMIT 25) AS "Join14" 
LEFT OUTER JOIN (
SELECT "Extent19"."Id", "Extent23"."Value", "Extent20"."SeriousInfringementId" FROM "dbo"."Premise" AS "Extent19" 
INNER JOIN "dbo"."PremiseSeriousInfringement" AS "Extent20" ON "Extent19"."Id" = "Extent20"."PremiseId" 
INNER JOIN "dbo"."SeriousInfringement" AS "Extent21" ON "Extent20"."SeriousInfringementId" = "Extent21"."Id" 
INNER JOIN "dbo"."SeriousInfringementCode" AS "Extent22" ON "Extent21"."SeriousInfringementCodeId" = "Extent22"."Id" 
INNER JOIN "dbo"."DictionaryValue" AS "Extent23" ON "Extent22"."SeriousInfringementTypeId" = "Extent23"."Id" WHERE "Extent19"."TransportManagerId" IS NOT NULL) AS "Join18" ON "Join14"."Id" = "Join18"."Id" OR TRUE = FALSE) AS "Project8" ORDER BY "Project8"."Type" ASC ,"Project8"."UndertakingId" ASC ,"Project8"."TransportManagerId" ASC ,"Project8"."CancelReasons" ASC ,"Project8"."WarningDate" ASC ,"Project8"."WarningDeliveryDate" ASC ,"Project8"."FinishDate" ASC ,"Project8"."InternalProceeding" ASC ,"Project8"."AuthorityId" ASC ,"Project8"."PenaltyImposed" ASC ,"Project8"."PenaltyDescription" ASC ,"Project8"."PenaltyType" ASC ,"Project8"."isSendToEpuap" ASC ,"Project8"."ModificationDate" ASC ,"Project8"."CreatedByAppUserId" ASC ,"Project8"."LastModifiedByAppUserId" ASC ,"Project8"."Id1" ASC ,"Project8"."Id" ASC ,"Project8"."Status" ASC ,"Project8"."CreationDate" ASC ,"Project8"."BusinessCaseNumber" ASC ,"Project8"."C1" ASC 

これはpgAdminでIIIによって提案された計画である:

PostGresql query plan

[編集]私の友人は、そのようなSQLを来た:

select premise."Id", premise."Type", premise."CreationDate", premise."Status", premise."BusinessCaseNumber", tm."FirstNames", tm."FamilyName",tm."CertificateNumber",premiseSum.NNCount, premiseSum.BPNCount, premiseSum.PNCount from 
(
    select distinct 
     premiseGroup."PremiseId", 

     sum(premiseGroup.NNCount) OVER (partition BY premiseGroup."PremiseId") NNCount, 
     sum(premiseGroup.BPNCount) OVER (partition BY premiseGroup."PremiseId") BPNCount, 
     sum(premiseGroup.PNCount) OVER (partition BY premiseGroup."PremiseId") PNCount 
    from 
    (
     select psi."PremiseId", 
      (select sum(count(sit."Value")) OVER (ORDER BY psi."PremiseId") where "Value" = 'NN') NNCount, 
      (select sum(count(sit."Value")) OVER (ORDER BY psi."PremiseId") where "Value" = 'PN') PNCount, 
      (select sum(count(sit."Value")) OVER (ORDER BY psi."PremiseId") where "Value" = 'BPN') BPNCount 
     from "dbo"."Premise" premise 
     inner join "dbo"."PremiseSeriousInfringement" psi on psi."PremiseId" = premise."Id" 
     inner join "dbo"."SeriousInfringement" si on psi."SeriousInfringementId" = si."Id" 
     inner join "dbo"."SeriousInfringementCode" sic on si."SeriousInfringementCodeId" = sic."Id" 
     inner join "dbo"."DictionaryValue" sit on sic."SeriousInfringementTypeId" = sit."Id" 
     group by psi."PremiseId", sit."Value" 
    ) premiseGroup 
) premiseSum 
join "dbo"."Premise" premise on premise."Id" = premiseSum."PremiseId" 
join "dbo"."TransportManager" tm on tm."Id" = premise."TransportManagerId" 

これは本当に高速で素敵なクエリプランですが、LINQとEFでこれを書く方法はわかりません。 QueryPlan2

答えて

1

私の経験では、EFは一般的に述語バージョンCountの非効率な翻訳を作成します。

私は通常行うが、はるかに優れたSQL(少なくともSQL Serverの場合)に変換同等の条件 Sum構築物( Sum(condition ? 1 : 0))と述語 Count構築物( Count(condition)を交換することでどのような

ので、試してみる価値だ:

let NNInfringementCount = types.Sum(t => t == "NN" ? 1 : 0) 
let BPNInfringementCount = types.Sum(t => t == "BPN" ? 1 : 0) 
let PNInfringementCount = types.Sum(t => t == "PN" ? 1 : 0) 
+0

これは高速ですが、あまり変更されていないため、EFはネストされたループを持つ3つのサブクエリを作成します。 –

関連する問題