添加条件查询会使时间增加超过2400%

时间:2016-01-07 18:02:22

标签: sql-server

更新:我会尽快得到查询计划。

我们的查询效果不佳,需要4分钟才能完成特定组织。在通常重新编译之后,存储过程和更新统计信息没有帮助,我们将if Exists(...)重写为选择计数(*)...以及从4分钟到70毫秒的存储过程。条件使得70毫秒查询需要4分钟的问题是什么?参见示例

这些都需要4分钟以上:

if (
  SELECT COUNT(*)       
    FROM ObservationOrganism  omo
    JOIN Observation          om  ON  om.ObservationID  = omo.ObservationMicID
    JOIN Organism             o   ON  o.OrganismID      = omo.OrganismID
    JOIN ObservationMicDrug   omd ON  omd.ObservationOrganismID = omo.ObservationOrganismID
    JOIN SIRN                 srn ON  srn.SIRNID        = omd.SIRNID
    JOIN OrganismDrug         od  ON  od.OrganismDrugID = omd.OrganismDrugID
  WHERE
    om.StatusCode IN ('F', 'C')
    AND o.OrganismGroupID <> -1
    AND od.OrganismDrugGroupID <> -1
    AND (om.LabType <> 'screen' OR om.LabType IS NULL)) > 0

print 'records';       

-

IF (EXISTS(
  SELECT *       
    FROM ObservationOrganism  omo
    JOIN Observation          om  ON  om.ObservationID  = omo.ObservationMicID
    JOIN Organism             o   ON  o.OrganismID      = omo.OrganismID
    JOIN ObservationMicDrug   omd ON  omd.ObservationOrganismID = omo.ObservationOrganismID
    JOIN SIRN                 srn ON  srn.SIRNID        = omd.SIRNID
    JOIN OrganismDrug         od  ON  od.OrganismDrugID = omd.OrganismDrugID
  WHERE
    om.StatusCode IN ('F', 'C')
    AND o.OrganismGroupID <> -1
    AND od.OrganismDrugGroupID <> -1
    AND (om.LabType <> 'screen' OR om.LabType IS NULL))

print 'records'

这一切都需要70毫秒:

Declare @recordCount INT;
SELECT @recordCount = COUNT(*)       
    FROM ObservationOrganism  omo
    JOIN Observation          om  ON  om.ObservationID  = omo.ObservationMicID
    JOIN Organism             o   ON  o.OrganismID      = omo.OrganismID
    JOIN ObservationMicDrug   omd ON  omd.ObservationOrganismID = omo.ObservationOrganismID
    JOIN SIRN                 srn ON  srn.SIRNID        = omd.SIRNID
    JOIN OrganismDrug         od  ON  od.OrganismDrugID = omd.OrganismDrugID
  WHERE
    om.StatusCode IN ('F', 'C')
    AND o.OrganismGroupID <> -1
    AND od.OrganismDrugGroupID <> -1
    AND (om.LabType <> 'screen' OR om.LabType IS NULL);

IF(@recordCount > 0)
  print 'records';

对我来说,为什么将完全相同的Count(*)查询移动到if语句会导致此类降级或为什么存在&#39;存在&#39;慢于Count。我甚至在exists()中尝试了select CASE WHEN Exists(),但仍然是4分钟以上。

1 个答案:

答案 0 :(得分:3)

鉴于我之前提到的答案,我会再次尝试解释,因为这些事情非常棘手。所以,是的,我认为你和the other question看到了同样的问题。即row goal问题。

因此,为了尝试解释造成这种情况的原因,我将从引擎处理的三种类型的连接开始(并且非常明确地说):循环连接,合并连接,哈希连接。循环连接就像它们听起来一样,是两组数据的嵌套循环。合并连接采用两个排序列表并以锁定步骤移动它们。哈希加入将较小的一切中的所有东西扔进文件柜,然后在文件柜填满后在较大的一套中查找物品。

因此,性能方面,循环连接几乎不需要设置,如果您只是寻找少量数据,那么它们确实是最佳的。就任何数据大小的连接性能而言,合并是最好的,但是要求数据已经排序(这种情况很少见)。散列连接需要相当多的设置,但允许快速连接大型数据集。

现在我们来看看您的查询以及COUNT(*)EXISTS/TOP 1之间的区别。因此,您看到的行为是优化程序认为此查询的行很可能(您可以通过计划查询而不进行分组并查看它认为在最后一步中将获得的记录数来确认)。特别是它可能认为对于该查询中的某些表,该表中的每个记录都将出现在输出中。

&#34;尤里卡&#34!;它说,&#34;如果这个表中的每一行最终都在输出中,为了找出是否存在,我可以在整个过程中进行非常便宜的启动循环连接,因为即使它对大型数据集来说速度慢,我只需要一排。&#34;但那时它并没有找到那一排。而且还没有找到它。现在,它正在使用效率最低的方法迭代大量数据,以便清除大量数据。

相比之下,如果您要求完整的数据计数,则必须按定义查找每条记录。它可以看到大量的数据,并选择最适合迭代整个数据集的选择,而不仅仅是一小部分数据。

另一方面,如果它确实是正确的并且记录非常相关,那么它将找到具有尽可能少的服务器资源的记录并最大化其总体吞吐量。