2014-12-04 44 views
0

这两个查询为什么会有这样的差异?针对特定键值的慢SQL SELECT

这个查询花费约51秒来完成:

SELECT TOP 1000 * 
FROM [PHONER].[dbo].[V_PhonerSubjects] 
WHERE ProjectID = 137; 

然而,这种查询采用约1秒至完成:

SELECT TOP 1000 * 
FROM [PHONER].[dbo].[V_PhonerSubjects] 
WHERE ProjectID = 107; 

注意:唯一的区别是关键的值。

两者共有超过1000条记录。项目107有26000条记录,项目137有4500条记录。

ProjectID是索引主键。

我注意到,第二个查询在1秒内​​完成并将所有行发送到结果窗口。第一个查询开始在大约3秒后发送行,并在大约51秒后完成。

这是查看V_PhonerSubjects的SQL:

SELECT   
    dbo.PhonerEmner.PhonerEmID AS SubjectID, dbo.PhonerEmner.FK_ProID AS ProjectID, 
    dbo.PhonerProjekt.PhonerTitel AS ProjectName, dbo.Medlemsdata.Vennenr AS FriendNo, 
    dbo.Medlemsdata.OpretteDato AS CreatedDate, dbo.Medlemsdata.OpretteID AS CreatedID, 
    dbo.Bruger.Intialer AS CreatedBy, dbo.Medlemsdata.ÆndretDato AS ChangedDate, 
    dbo.Medlemsdata.ÆndretID AS ChangedID, 
    Bruger_3.Intialer AS ChangedBy, 
    ISNULL(dbo.Medlemsdata.Organisation, N'') + N' ' + ISNULL(dbo.Medlemsdata.Fornavn, N'') + N' ' + ISNULL(dbo.Medlemsdata.Efternavn, N'') AS Name, 
    dbo.MedlemsAdresse.AdrID AS AddressID, dbo.MedlemsAdresse.Adresse AS Address1, 
    dbo.MedlemsAdresse.Adresse2 AS Address2, dbo.MedlemsAdresse.Postnr AS ZIP, 
    dbo.Postnumre.[By] AS City, dbo.Medlemsdata.CPRnr AS CPRno, 
    dbo.Medlemsdata.Køn AS Gender, dbo.Medlemsdata.Telefon AS Phone01, 
    dbo.Medlemsdata.TlfNote1 AS Phone02Type, dbo.Medlemsdata.Tlf1 AS Phone02, 
    dbo.Medlemsdata.TlfNote2 AS Phone03Type, dbo.Medlemsdata.Tlf2 AS Phone03, 
    dbo.Medlemsdata.TlfNote3 AS Phone04Type, 
    dbo.Medlemsdata.Tlf3 AS Phone04, dbo.Medlemsdata.TlfSMS AS PhoneMobile, 
    dbo.Medlemsdata.[E-mail] AS Email, dbo.Medlemsdata.SPFelt1 AS SPField01, 
    dbo.Medlemsdata.SPFelt2 AS SPField02, dbo.Medlemsdata.SPFelt3 AS SPField03, 
    dbo.Medlemsdata.SPFelt4 AS SPField04, dbo.Medlemsdata.SPFelt5 AS SPField05, 
    dbo.Medlemsdata.SPFelt6 AS SPField06, dbo.Medlemsdata.SPFelt7 AS SPField07, 
    dbo.Medlemsdata.SPFelt8 AS SPField08, dbo.Medlemsdata.SPFelt9 AS SPField09, 
    dbo.Medlemsdata.SPFelt10 AS SPField10, dbo.Medlemsdata.SPFelt11 AS SPField11, 
    dbo.Medlemsdata.SPFelt12 AS SPField12, dbo.Medlemsdata.SPFelt13 AS SPField13, 
    dbo.Medlemsdata.SPFelt14 AS SPField14, dbo.PhonerEmner.SidsteKontakt AS LastContact, 
    dbo.PhonerEmner.AntalKontakt AS ContactTimes, dbo.PhonerEmner.KontaktDage AS ContactDays, 
    dbo.PhonerEmner.KontaktEfter AS ContactAfter, 
    dbo.PhonerEmner.PhonerIgen AS ContactAfterPhonerID, 
    Bruger_1.Navn AS ContactAfterPhonerName, dbo.PhonerEmner.PhonerNote, 
    dbo.PhonerEmner.Stemning AS Mood, dbo.PhonerEmner.Status, 
    dbo.PhonerEmner.PhonerAft AS LastPhonerID, Bruger_2.Navn AS LastPhonerName, 
    dbo.PhonerEmner.SlutNote AS EndNote, dbo.PhonerEmner.SlutDato AS EndDate, 
    dbo.PhonerImport.PhonerImportID AS ImportID, dbo.PhonerImportData.Status AS ImportStatus, 
    dbo.PhonerImport.ImportFileName, dbo.PhonerImport.ImportTime, 
    dbo.PhonerProjekt.SvarerIkkeTid 
FROM    
    dbo.Bruger AS Bruger_1 
RIGHT OUTER JOIN 
    dbo.PhonerProjekt 
RIGHT OUTER JOIN 
    dbo.PhonerEmner ON dbo.PhonerProjekt.PhonerProID = dbo.PhonerEmner.FK_ProID 
LEFT OUTER JOIN 
    dbo.PhonerImportData ON dbo.PhonerEmner.PhonerEmID = dbo.PhonerImportData.FK_PhonerEmID 
LEFT OUTER JOIN 
    dbo.Bruger AS Bruger_2 ON dbo.PhonerEmner.PhonerAft = Bruger_2.BrugerID ON Bruger_1.BrugerID = dbo.PhonerEmner.PhonerIgen 
LEFT OUTER JOIN 
    dbo.Bruger 
RIGHT OUTER JOIN 
    dbo.Bruger AS Bruger_3 
RIGHT OUTER JOIN 
    dbo.Medlemsdata ON Bruger_3.BrugerID = dbo.Medlemsdata.ÆndretID ON dbo.Bruger.BrugerID = dbo.Medlemsdata.OpretteID ON dbo.PhonerEmner.FK_Vennenr = dbo.Medlemsdata.Vennenr 
LEFT OUTER JOIN 
    dbo.Postnumre 
RIGHT OUTER JOIN 
    dbo.MedlemsAdresse ON dbo.Postnumre.Postnummer = dbo.MedlemsAdresse.Postnr ON dbo.Medlemsdata.FK_AdrID = dbo.MedlemsAdresse.AdrID 
LEFT OUTER JOIN 
    dbo.PhonerImport ON dbo.PhonerImportData.FK_PhonerImportID = dbo.PhonerImport.PhonerImportID 

项目107客户端统计:

Client Execution Time 14:04:24   
Query Profile Statistics    
    Number of INSERT, DELETE and UPDATE statements 0  0.0000 
    Rows affected by INSERT, DELETE, or UPDATE statements 0  0.0000 
    Number of SELECT statements 2  2.0000 
    Rows returned by SELECT statements 1001  1001.0000 
    Number of transactions 0  0.0000 
Network Statistics   
    Number of server roundtrips 3  3.0000 
    TDS packets sent from client 3  3.0000 
    TDS packets received from server 241  241.0000 
    Bytes sent from client 340  340.0000 
    Bytes received from server 976874  976874.0000 
Time Statistics   
    Client processing time 95  95.0000 
    Total execution time 391  391.0000 
    Wait time on server replies 296  296.0000 

项目137客户端统计:

Client Execution Time 13:58:28   
Query Profile Statistics    
    Number of INSERT, DELETE and UPDATE statements 0  0.0000 
    Rows affected by INSERT, DELETE, or UPDATE statements 0  0.0000 
    Number of SELECT statements 2  2.0000 
    Rows returned by SELECT statements 1001  1001.0000 
    Number of transactions 0  0.0000 
Network Statistics   
    Number of server roundtrips 3  3.0000 
    TDS packets sent from client 3  3.0000 
    TDS packets received from server 217  217.0000 
    Bytes sent from client 340  340.0000 
    Bytes received from server 877700  877700.0000 
Time Statistics   
    Client processing time 129596  129596.0000 
    Total execution time 130297  130297.0000 
    Wait time on server replies 701  701.0000 
+1

如果您为两个语句单独提供查询执行计划可能会有所帮助。在SQL Management Studio中,选择“包括实际执行计划”图标(或使用Ctrl + M将其切换),并在查询完成后获取执行计划,该计划将作为标签为“执行计划”的选项卡提供查询结果窗格。这些执行计划对于每个查询分别是什么样的? – Seibar 2014-12-04 20:32:44

+2

也许过时的统计数据?在执行计划中检查估计的行与实际行返回 – 2014-12-04 20:35:17

+0

请发布2查询计划。 – 2014-12-04 21:00:06

回答

0

鉴于少行运行速度较慢,我会怀疑数据内容,而不是架构。

如果一个数据集在大多数OUTER JOIN上找到匹配项,而另一个则不匹配,这可能会导致运行时的一些差异。加入时,一个小姐只是指数,但一个表中读取结果。

+0

这也是我第一次怀疑。但更多的是其他方式。例如,项目107有35个关联的导入文件,其中项目137只有3个。 – 2014-12-05 12:48:40

1

左右连接的复杂混乱以及查询的非关联可读性可能会成为问题的一部分。我可能完全错误,并接受。但是,我基于从各个表到所有下一级的所有层次连接标准重新构造您的查询...每个表“JOIN”ed和“ON”条件直接作为关联vs混合。在这里,你可以从层次上看到这些表格与相关的细节。我还使用ALIASES从原始文章更好的可读性。

所以,看起来你有一些手机项目加入到PhonerEmner表中。基于这些元素,您试图尽可能多地查找二次数据。如果它存在,很好,得到它,但不要停止,如果没有在子级相关表中找到这样的记录。这样,它们都是LEFT JOIN。如果您希望在任何给定表中都需要记录,只需从LEFT JOIN更改为INNER JOIN,并/或添加WHERE子句以确保找到给定的别名.ID列。

所有这一切说,我会确保该表有索引才能正确地优化通过加入..

table   index 
PhonerEmner  (FK_ProID, PhonerIgen, PhonerEmID, PhonerAft, FK_Vennenr 
PhonerProjekt (PhonerProID) 
Bruger   (BrugerID 
PhonerImportData (FK_PhonerEmID, FK_PhonerImportID 
PhonerImport  (PhonerImportID 
Medlemsdata  (Vennenr, OpretteID, ÆndretID, FK_AdrID) 
MedlemsAdresse (AdrID, Postnr) 
Postnumre  (Postnummer) 

,并与您可以创建一个新的视图来测试针对此修订查询上来。

SELECT 
     PE.PhonerEmID AS SubjectID, 
     PE.FK_ProID AS ProjectID, 
     PP.PhonerTitel AS ProjectName, 
     MED.Vennenr AS FriendNo, 
     MED.OpretteDato AS CreatedDate, 
     MED.OpretteID AS CreatedID, 
     B.Intialer AS CreatedBy, 
     MED.ÆndretDato AS ChangedDate, 
     MED.ÆndretID AS ChangedID, 
     B3.Intialer AS ChangedBy, 
     ISNULL(MED.Organisation, N'') 
     + N' ' + ISNULL(MED.Fornavn, N'') 
     + N' ' + ISNULL(MED.Efternavn, N'') AS Name, 
     ADR.AdrID AS AddressID, 
     ADR.Adresse AS Address1, 
     ADR.Adresse2 AS Address2, 
     ADR.Postnr AS ZIP, 
     PST.[By] AS City, 
     MED.CPRnr AS CPRno, 
     MED.Køn AS Gender, 
     MED.Telefon AS Phone01, 
     MED.TlfNote1 AS Phone02Type, 
     MED.Tlf1 AS Phone02, 
     MED.TlfNote2 AS Phone03Type, 
     MED.Tlf2 AS Phone03, 
     MED.TlfNote3 AS Phone04Type, 
     MED.Tlf3 AS Phone04, 
     MED.TlfSMS AS PhoneMobile, 
     MED.[E-mail] AS Email, 
     MED.SPFelt1 AS SPField01, 
     MED.SPFelt2 AS SPField02, 
     MED.SPFelt3 AS SPField03, 
     MED.SPFelt4 AS SPField04, 
     MED.SPFelt5 AS SPField05, 
     MED.SPFelt6 AS SPField06, 
     MED.SPFelt7 AS SPField07, 
     MED.SPFelt8 AS SPField08, 
     MED.SPFelt9 AS SPField09, 
     MED.SPFelt10 AS SPField10, 
     MED.SPFelt11 AS SPField11, 
     MED.SPFelt12 AS SPField12, 
     MED.SPFelt13 AS SPField13, 
     MED.SPFelt14 AS SPField14, 
     PE.SidsteKontakt AS LastContact, 
     PE.AntalKontakt AS ContactTimes, 
     PE.KontaktDage AS ContactDays, 
     PE.KontaktEfter AS ContactAfter, 
     PE.PhonerIgen AS ContactAfterPhonerID, 
     B1.Navn AS ContactAfterPhonerName, 
     PE.PhonerNote, 
     PE.Stemning AS Mood, 
     PE.Status, 
     PE.PhonerAft AS LastPhonerID, 
     B2.Navn AS LastPhonerName, 
     PE.SlutNote AS EndNote, 
     PE.SlutDato AS EndDate, 
     PI.PhonerImportID AS ImportID, 
     PID.Status AS ImportStatus, 
     PI.ImportFileName, PI.ImportTime, 
     PP.SvarerIkkeTid 
    FROM 
     dbo.PhonerEmner PE 
     LEFT JOIN dbo.PhonerProjekt PP 
      ON PE.FK_ProID = PP.PhonerProID 
     LEFT JOIN dbo.Bruger B1 
      ON PE.PhonerIgen = B1.BrugerID 
     LEFT JOIN dbo.PhonerImportData PID 
      ON PE.PhonerEmID = PID.FK_PhonerEmID 
      LEFT JOIN dbo.PhonerImport PI 
       ON PID.FK_PhonerImportID = PI.PhonerImportID 
     LEFT JOIN dbo.Bruger B2 
      ON PE.PhonerAft = B2.BrugerID 
     LEFT JOIN dbo.Medlemsdata MED 
      ON PE.FK_Vennenr = MED.Vennenr 
      LEFT JOIN dbo.Bruger B 
       ON MED.OpretteID = B.BrugerID 
      LEFT JOIN dbo.Bruger B3 
       ON MED.ÆndretID = B3.BrugerID 
      LEFT JOIN dbo.MedlemsAdresse ADR 
       ON MED.FK_AdrID = ADR.AdrID 
       LEFT JOIN dbo.Postnumre PST 
        ON ADR.Postnr = PST.Postnummer 
+0

我实施了您的建议并确保上述索引已生成。根本没有改变。可读性低的原因是由于Microsoft SQL Management Studio的视图设计师。 – 2014-12-05 12:51:51

+0

@JackW.Jensen,我了解设计师试图为你思考的问题。你是否以独立视图的形式进行操作,并从中进行查询......或者是否创建了第二个视图,但是是从原始视图进行查询。听起来不好,但我甚至有时脑痉挛:) – DRapp 2014-12-05 13:40:16

+0

它是一种视图,是搜索工具的基础。搜索工具构建一个where条件并从视图中检索结果。 – 2014-12-05 15:44:38

0

我发现了这个问题。

我改变了连接。对我来说,不管我是以这种方式还是以另一种方式做到了这一点,但显然它确实如此。

而不是将PhonerEmner加入PhonerEmID = PhonerEmID = FK_PhonerEmID上的PhonerImportData。我在Vennenr = FK_Vennenr加入MedlemsData到PhonerImportData。它必须与PhonerEmID不是主键,而只是索引有关。