相同的查询,相同的DB,不同的执行计划&执行

时间:2017-06-28 05:26:07

标签: sql-server

我遇到了一个我无法理解的问题。我们正在运行SQL Server 2012.我遇到了一对基本相同的查询,这些查询产生了不同的执行计划和执行的时间差异很大(1秒vs 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倍的执行时间?

最终,我不知道如何改善第二个查询的糟糕表现,因为我可以理解两者之间没有本质区别。

2 个答案:

答案 0 :(得分: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.products删除第一个以上索引的CLUSTERED PRIMARY KEY替换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) 的NONCLUSTERED PRIMARY KEY(一个表不能有两个或更多个聚簇)索引)。

[2]我还会重写以下子查询

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)

因此:

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

对于这个子查询,我将创建以下非聚簇索引

[3]

GradientDrawable gradientDrawable=new GradientDrawable();
gradientDrawable.setShape(GradientDrawable.OVAL);
gradientDrawable.setColor(getResources().getColor(R.color.colorAccent));
gradientDrawable.setSize(200,200);
gradientDrawable.setCornerRadius(100);

答案 1 :(得分:0)

此问题是description列。 idCategory [628]的description长度比idCategory [494]长。因为您使用的是SP.description LIKE N'%(9-12 Months)'description的长度太长,然后你慢慢来。

您还在使用ORDER BY P.description Asc