2017-06-28 80 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列。 –

相關問題