更新:我会尽快得到查询计划。
我们有一个执行不佳的查询,一个特定的组织花了4分钟。在通常重新编译存储的proc和更新统计信息没有帮助之后,我们重新编写了if存在(.)选择计数(*)..。和存储过程时,从4分钟到70毫秒。使70 ms查询耗时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语句中会导致这种退化,或者为什么“存在”比Count慢,这对我来说是没有意义的。我甚至在select CASE WHEN Exists()中尝试过select CASE WHEN Exists(),它仍然是4+分钟。
发布于 2016-01-12 04:29:32
考虑到前面提到的答案,我会再解释一遍,因为这些问题相当棘手。所以是的,我想你看到的问题和另一个问题是一样的。即排目标问题。
因此,为了解释造成这种情况的原因,我将从引擎可用的三种连接类型开始:循环连接、合并连接、哈希连接。循环连接听起来就像在这两组数据上的嵌套循环。合并连接采用两个排序列表,并在锁定步骤中移动它们。Hash加入,将小集合中的所有东西都扔到文件柜中,然后在文件柜填满后在更大的一组中查找项目。
因此,就性能而言,循环联接几乎不需要设置,而且如果您只是在寻找少量数据,它们实际上是最优的。对于任何数据大小,合并都是最好的连接性能最好的,但要求数据已经被排序(这是罕见的)。散列连接需要相当数量的设置,但允许快速连接大型数据集。
现在我们来看看您的查询,以及COUNT(*)和EXISTS/TOP 1之间的区别。因此,您所看到的行为是,优化器认为这个查询的行非常有可能(您可以通过规划查询来确认这一点,而不需要分组并查看它认为在最后一步中将得到多少记录)。特别是,它可能认为对于该查询中的某个表,该表中的每条记录都将出现在输出中。
“尤里卡”它说,“如果这个表中的每一行都在输出中结束,为了找出是否存在一个行,我可以在整个过程中进行真正廉价的启动循环连接,因为即使对于大型数据集来说它很慢,但我只需要一行。”但它找不到那一排。再也找不到了。现在,它正在迭代大量的数据,使用最不有效的方法来清除大量的数据。
相比之下,如果您要求完整的数据计数,它必须找到每一个记录的定义。它看到了大量的数据,并选择了最适合迭代整组数据的选择,而不仅仅是其中的一小部分。
另一方面,如果它确实是正确的,并且记录是非常相关的,那么它就会发现您的记录具有尽可能少的服务器资源,并且最大限度地提高了它的总体吞吐量。
https://stackoverflow.com/questions/34662081
复制相似问题