回答

收藏

投影内相关子查询的排序的影响

技术问答 技术问答 252 人阅读 | 0 人回复 | 2023-09-12

我注意到SQL Server(本例为SQL Server
# U/ F" D7 m+ x/ ]( {2008)如何处理select语句中的相关子查询有些意外。我的假设是,查询计划不应仅在受子查询(或相应列)中select语句的projection子句中写入顺序的影响。但事实并非如此。1 |& x% C7 R, \! _# @) O
请考虑以下两个查询,除了CTE除中子查询顺序外,其余两个查询均相同:" [8 R1 }3 i9 j$ ?! }8 a! M
--query 1: subquery for Color is secondWITH vw AS( SELECT p.[ID], (SELECT TOP(1) [FirstName] FROM [Preference] WHERE p.ID = ID AND [FirstName] IS NOT NULL ORDER BY [LastModified] DESC) [FirstName], (SELECT TOP(1) [Color] FROM [Preference] WHERE p.ID = ID AND [Color] IS NOT NULL ORDER BY [LastModified] DESC) [Color] FROM Person p)SELECT ID,Color,FirstNameFROM vwWHERE Color = 'Gray';--query 2: subquery for Color is firstWITH vw AS( SELECT p.[ID],    (SELECT TOP(1) [Color] FROM [Preference] WHERE p.ID = ID AND [Color] IS NOT NULL ORDER BY [LastModified] DESC) [Color], (SELECT TOP(1) [FirstName] FROM [Preference] WHERE p.ID = ID AND [FirstName] IS NOT NULL ORDER BY [LastModified] DESC) [FirstName] FROM Person p)SELECT ID,Color,FirstNameFROM vwWHERE Color = 'Gray';如果您查看这两个查询计划,您将看到每个子查询都使用一个外部连接,连接顺序与子查询的写入顺序相同。过滤器用于颜色的外部连接,以过滤颜色不是灰色的线路。(对我来说,SQL使用外部连接颜色子查询是很奇怪的,因为我对颜色子查询的结果不是null约束,但是可以。)
1 n  T! p# M2 s3 P7 O1 R大多数行都被过滤器删除了。因此,查询2比查询1便宜得多,因为第二个连接涉及的线路较少。除了构建这些句子的所有原因外,这是预期的行为吗?无论子查询的写入顺序如何,SQL# ~: y7 ]+ l+ t5 A+ l  @
Server查询计划中不应选择尽快移动过滤器吗?* D8 U! `) i8 F9 x/ j$ p
编辑:5 J+ l% E) I9 N* p' _
只是为了澄清一个有效的原因,我正在探索这种情况。我可能需要创建一个包含类似结构的子查询视图。现在很明显,基于这些视图的任何过滤都会因为列的顺序而导致性能变化!
  q3 R! W4 R0 V" H                                                               
5 M; {+ r9 I+ {9 {    解决方案:                                                                ) H- V1 W  B% }! V( r
                                                                这是一个可能性更好的替代版本:9 l/ W6 |& V, A; ?) V5 f
With Colors As    (    Select Id,[Color] ROW_NUMBER() OVER ( PARTITION BY ID ORDER BY [LastModified] DESC ) As Num    From Preference    Where [Color] Is Not Null   Names As    (    Select Id,[FirstName] ROW_NUMBER() OVER ( PARTITION BY ID ORDER BY [LastModified] DESC ) As Num    From Preference    Where [FirstName] Is Not Null    )SelectFrom Person As P    Join Colors As C        On C.Id = P.Id            And C.Num = 1    Left Join Names As N        On N.Id = P.Id            And N.Num = 1Where C.[Color]= 'Grey'另一个更简单但可能效果不佳的解决方案:
6 S/ J0 X+ {0 d- p* c, S, kWith RankedItems    (    Select Id,[Color],[FirstName] ROW_NUMBER() OVER ( PARTITION BY ID ORDER BY Case When [Color] Is Not Null 1 Else 0 End DESC,[LastModified] DESC ) As ColorRank ROW_NUMBER() OVER ( PARTITION BY ID ORDER BY Case When [FirstName] Is Not Null 1 Else 0 End DESC,[LastModified] DESC ) As NameRank    From Preference    )SelectFrom Person As P    Join RankedItems As RI        On RI.Id = P.Id            And RI.ColorRank = 1    Left Join RankedItems As RI2          On RI2.Id = P.Id            And RI2.NameRank = 1Where RI.[Color]= 'Grey
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则