【问题标题】:Equivalent Queries, different results and execution time等效查询,不同的结果和执行时间
【发布时间】:2016-04-07 19:14:08
【问题描述】:

编辑:查询计划链接到:

Bad Query

Good Query

所以我正在研究一个 MSSQL 系统,并且我正在重写一些查询。我决定主要通过将谓词从 WHERE 子句中移出并将它们填充到我的 JOIN 子句中来使用我的谓词。当我这样做时,它返回的行数是原来的两倍,执行时间从几秒到几分钟。

我想知道发生了什么,因为我认为查询分析器通常会将谓词填充到 JOIN 子句中,因为这些行最终会被丢弃。

任何关于为什么这些查询不等价的帮助将不胜感激,我只是不够强大,不知道在哪里看..

好查询:

FROM [CONNECT_PROD].[dbo].[CRM_C005] c005 
LEFT JOIN [CONNECT_PROD].[dbo].[CRM_FI] fi ON c005.ID_FI = fi.ID
LEFT JOIN [CONNECT_PROD].[dbo].[CRM_CPPE] kp ON c005.ID_PE = kp.ID_PE AND  fi.id = kp.id_fi
LEFT JOIN [CONNECT_PROD].[dbo].[CRM_KA] vko ON c005.F7010 = vko.code 
LEFT JOIN [CONNECT_PROD].[dbo].[CRM_VF] vf on vf.id_fi = fi.id and vf.VerkOrg = vko.code
LEFT JOIN [CONNECT_PROD].[dbo].[CRM_KA] land ON fi.land = land.code 
LEFT JOIN [CONNECT_PROD].[dbo].[CRM_KA] title ON kp.Titel = title.code and title.loskz = 0 and title.KatSperre = 0 and title.sprachenr = 0 and title.katnr = 23
WHERE kp.loskz = 0
and vko.loskz = 0
and vko.KatSperre = 0
and vko.sprachenr = 0
and vko.katnr = 274
and vko.ExtKey = '0014'
and land.loskz = 0
and land.KatSperre = 0
and land.sprachenr = 1000
and land.katnr = 2
and fi.loskz = 0
and fi.F7029 = 0
and vf.loskz = 0
and vf.F7023 = 0
and vf.F7152 = 0
and c005.del = 0
and kp.f7017 = 0

错误查询:

FROM [CONNECT_PROD].[dbo].[CRM_C005] c005 
LEFT JOIN [CONNECT_PROD].[dbo].[CRM_FI] fi ON c005.ID_FI = fi.ID AND fi.loskz = 0 AND fi.F7029 = 0
LEFT JOIN [CONNECT_PROD].[dbo].[CRM_CPPE] kp ON c005.ID_PE = kp.ID_PE AND fi.id = kp.id_fi AND kp.loskz = 0 AND kp.f7017 = 0
LEFT JOIN [CONNECT_PROD].[dbo].[CRM_KA] vko ON c005.F7010 = vko.code AND vko.loskz = 0 AND vko.KatSperre = 0 AND vko.sprachenr = 0 AND vko.katnr = 274 and vko.ExtKey = '0014'
LEFT JOIN [CONNECT_PROD].[dbo].[CRM_VF] vf on vf.id_fi = fi.id and vf.VerkOrg = vko.code AND vf.loskz = 0 AND vf.F7023 = 0 AND vf.F7152 = 0
LEFT JOIN [CONNECT_PROD].[dbo].[CRM_KA] land ON fi.land = land.code AND land.loskz = 0 AND land.KatSperre = 0 AND land.sprachenr = 1000 AND land.katnr = 2
LEFT JOIN [CONNECT_PROD].[dbo].[CRM_KA] title ON kp.Titel = title.code and title.loskz = 0 and title.KatSperre = 0 and title.sprachenr = 0 and title.katnr = 23
WHERE c005.del = 0

【问题讨论】:

  • 请提供执行计划
  • 查询是不一样的,因为在左外连接的情况下,条件只会限制从外连接表中获取的行,并且仍然会从 CRM_C005 中获取行,但在原始查询中它将离开完全取出行——因此在 where 子句中包含与外连接相关的任何内容都会将其变成内连接。
  • @dfundako SO 有首选上传位置吗?
  • @dfundako 完成,计划已添加。

标签: sql-server tsql join


【解决方案1】:

假设这个例子:我有一个包含 100,000 个电话的表格。有某些类型的电话:呼入和呼出。当我写一个查询是

SELECT * 
FROM calls c
LEFT JOIN calltypes ct
ON c.calltypeID = ct.calltypeID
WHERE c.calltypeID = 1 --Assume this is inbound

此查询将仅返回我的呼叫表中的入站呼叫。

现在,如果我写:

SELECT * 
    FROM calls c
    LEFT JOIN calltypes ct
    ON c.calltypeID = ct.calltypeID
    AND c.calltypeID = 1 

我将返回 100,000 行。左连接找不到合适的连接条件,所以对 ct 表的值返回空值。这是一个示例,说明当您在连接条件中使用 where 子句时,您的查询可能会返回更多的行。

【讨论】:

  • 天哪,我是怎么走到这一步却不知道有什么区别的!我总是把我的“c.calltypeID”放在 WHERE 子句中,所以我想我从来不需要学习。但我可以看到这些额外的行将如何通过使我的结果集膨胀的序列。
  • 是的,您正在将原始查询中的左连接转换为内连接。它与您编写的查询不同。如果您一直这样做,那么您可能有许多查询返回不正确的结果。
【解决方案2】:

通过在您将其变为常规连接的位置引用连接的外侧
你也可以这样做

FROM [CONNECT_PROD].[dbo].[CRM_C005] c005 
JOIN [CONNECT_PROD].[dbo].[CRM_FI] fi 
       ON fi.ID    = c005.ID_FI 
      and            c005.del = 0
      and fi.loskz = 0
      and fi.F7029 = 0
JOIN [CONNECT_PROD].[dbo].[CRM_CPPE] kp 
       ON kp.ID_PE = c005.ID_PE  
      AND kp.id_fi = c005.ID_FI 
      and kp.loskz = 0 
      and kp.f7017 = 0
JOIN [CONNECT_PROD].[dbo].[CRM_KA] vko 
       ON vko.code      = c005.F7010     
      and vko.loskz     = 0
      and vko.KatSperre = 0
      and vko.sprachenr = 0
      and vko.katnr     = 274
      and vko.ExtKey    = '0014'
JOIN [CONNECT_PROD].[dbo].[CRM_VF] vf 
       on vf.id_fi   = c005.ID_FI 
      and vf.VerkOrg = vko.code 
      and vf.loskz   = 0
      and vf.F7023   = 0
      and vf.F7152   = 0
JOIN [CONNECT_PROD].[dbo].[CRM_KA] land 
       ON land.code      = fi.land  
      and land.loskz     = 0
      and land.KatSperre = 0
      and land.sprachenr = 1000
      and land.katnr     = 2
JOIN [CONNECT_PROD].[dbo].[CRM_KA] title 
       ON title.code      = kp.Titel 
      and title.loskz     = 0 
      and title.KatSperre = 0 
      and title.sprachenr = 0 
      and title.katnr     = 23

【讨论】:

    猜你喜欢
    • 2016-05-03
    • 2011-04-24
    • 2015-09-15
    • 2013-10-05
    • 1970-01-01
    • 2014-08-23
    • 1970-01-01
    • 2016-02-08
    • 1970-01-01
    相关资源
    最近更新 更多