2017-06-28 83 views
1

我遇到了一个问题,我无法理解。我们正在运行SQL Server 2012.我遇到了一对基本相同的查询,这些查询产生不同的执行计划,并且执行的时间显着不同(1秒比40+秒)...并且他们甚至返回完全相同的记录。它们之间唯一的区别是记录被查询的类别。相同的查询,相同的数据库,不同的执行计划和执行的时间显着不同

该查询在1秒钟内运行:

SELECT P.idProduct, P.sku, P.description, P.price, P.listhidden, P.listprice, P.serviceSpec, P.bToBPrice, P.smallImageUrl,P.noprices,P.stock, P.noStock,P.pcprod_HideBTOPrice,P.pcProd_BackOrder,P.FormQuantity,P.pcProd_BTODefaultPrice,cast(P.sDesc as varchar(8000)) sDesc, 0, 0, P.pcprod_OrdInHome, P.sales, P.pcprod_EnteredOn, P.hotdeal, P.pcProd_SkipDetailsPage 
FROM products P INNER JOIN categories_products CP ON P.idProduct = CP.idProduct 
WHERE CP.idCategory=494 AND active=-1 AND configOnly=0 and removed=0 AND formQuantity=0 
AND ((SELECT TOP 1 SP.stock FROM products SP WHERE SP.pcprod_ParentPrd = P.idProduct AND SP.description LIKE N'%(9-12 Months)' AND SP.removed=0) > 0) 
ORDER BY P.description Asc 

第二个运行40秒多,但唯一的区别是idCategory查询:

SELECT P.idProduct, P.sku, P.description, P.price, P.listhidden, P.listprice, P.serviceSpec, P.bToBPrice, P.smallImageUrl,P.noprices,P.stock, P.noStock,P.pcprod_HideBTOPrice,P.pcProd_BackOrder,P.FormQuantity,P.pcProd_BTODefaultPrice,cast(P.sDesc as varchar(8000)) sDesc, 0, 0, P.pcprod_OrdInHome, P.sales, P.pcprod_EnteredOn, P.hotdeal, P.pcProd_SkipDetailsPage 
FROM products P INNER JOIN categories_products CP ON P.idProduct = CP.idProduct 
WHERE CP.idCategory=628 AND active=-1 AND configOnly=0 and removed=0 AND formQuantity=0 
AND ((SELECT TOP 1 SP.stock FROM products SP WHERE SP.pcprod_ParentPrd = P.idProduct AND SP.description LIKE N'%(9-12 Months)' AND SP.removed=0) > 0) 
ORDER BY P.description Asc 

他们甚至返回完全相同的记录完全相同的顺序。

为第一查询执行计划:enter image description here

的第二查询执行计划: enter image description here

[编辑]这里的计划是实际,而不是估计,执行计划。

categories_products表是一个简单的查找表,只有两个字段idCategoryidProduct。即使是返回的记录也完全一样(只是碰巧SP.description LIKE N'%(9-12 Months)',同样的产品被分配到这两个类别)。两者之间唯一的另一个区别是CP.idCategory 628是在今天早上刚刚创建的(但我没有看到可能会产生什么差异)。 [编辑:但是这正是没赚差价]

怎么能这样呢?如何简单地改变这里查询的CP.idCategory会产生一个不同的执行计划,更重要的是:它是如何执行40倍的执行时间?

最终,我不知所措弄清楚如何改善因为有两个,我可以理解没有本质区别,第二查询的可怕表现。

+0

因此,如果你悬停ov呃两种情况下的_products_表扫描,它在搜索什么?如果你运行这个并包含_actual_计划,你是否看到实际和估计行数有差异? –

+0

也可能是第二个查询有一个错误的缓存计划,第一个查询没有。 –

+0

当大量的行被添加或修改时,我偶尔会看到类似的行为。通常它帮助我手动刷新涉及表的统计信息。但执行计划(针对慢速查询)明确指出缺少索引。尝试创建它,看看会发生什么... – user1429080

回答

0

这个问题description列。 idCategory [628]的长度为description,长度大于idCategory [494]。因为你正在使用SP.description LIKE N'%(9-12 Months)'description的长度太长,那么你慢慢来。

而且你正在使用ORDER BY P.description Asc

+0

谢谢@Tien Nguyen,但是'description'列属于'products'表,在这种情况下两个查询的结果记录集完全相同。所以这里所有'描述'的长度都是一样的。 – KPsean

+0

我明白了。 idCategory [628]和idCategory [494]中有多少产品?并且每个产品都必须使用**描述LIKE **。所以它会很慢。 –

2

[1]看来,两个不同的类别可以有不同的最优的执行计划。在这种情况下,SQL Server似乎认为最适合idCategory=494的XP不是最优的idCategory=628WHERE CP.idCategory=494/WHERE CP.idCategory=628)。这个问题的

根源似乎是一个事实,即dbo.products表没有一个聚集索引。首先测试将是这样创造的CIX:

CREATE UNIQUE CLUSTERED INDEX IUC_products 
ON dbo.products(UniqueColumn_ID) 

如果经过反复试验,性能好两个查询我将取代dbo.productsCLUSTERED PRIMARY KEY的NONCLUSTERED PRIMARY KEY第一滴速上述指数(一个表卡恩” t有两个或更多的聚集索引)。

[2]此外,我将重写以下子查询

AND ((SELECT TOP 1 SP.stock FROM products SP WHERE SP.pcprod_ParentPrd = P.idProduct AND SP.description LIKE N'%(9-12 Months)' AND SP.removed=0) > 0) 

从而:

AND EXISTS(SELECT * FROM products SP WHERE SP.pcprod_ParentPrd = P.idProduct AND SP.description LIKE N'%(9-12 Months)' AND SP.removed=0 AND SP.stock > 0) 

和用于此子查询我想创建以下非聚集索引

[3]

CREATE NONCLUSTERED INDEX IX_product_pcprod_ParentPrd_removed_stock 
ON dbo.products (pcprod_ParentPrd, removed, stock) 
INCLUDE (description) 
+0

感谢Bogdan Sahlean的建议。我正在探索一个开发地点的#1和#3,一旦我尝试过它们,我们会进一步评论。 我很欣赏你的#2,但并不是很明显,子查询只返回'SP.stock'> 0的记录,即“有货”。但是,为了获得数据结构所需的记录集,该子查询的不幸需求绝对是查询和XP的一部分,这些查询和事件可能会陷入停滞。 – KPsean

+0

如果有必要,可以在子查询中添加其他条件,例如'SP.stock> 0'。 –

+0

我更新了[3],以便将'stock'列作为索引键的一部分,而不仅仅是一个'INCLUDE'd列。 –

相关问题