簡體   English   中英

單獨運行時查詢速度快,但在連接內添加時查詢速度慢

[英]Query fast when run separately but slow when added inside a join

在 SQL 服務器上,這個查詢運行的非常快,不到一秒:

SELECT T1.id
FROM first AS T1
WHERE T1.id = 21

這個查詢也運行得非常快,不到一秒,盡管它有 5300 萬條記錄,但 id 21 只有大約 6 條記錄:

SELECT TOP 1 T2.value
FROM second AS T2 WITH(INDEX(IX_second))
WHERE T2.id = 21 
  AND T2.b = 1 
  AND T2.c = 0 
  AND T2.d = 0 
  AND T2.e = 0
ORDER BY T2.id, T2.b, T2.c, T2.d, T2.e, T2.timestamp DESC

但是,我用 T1.id 替換內部SELECT中的 21 的這個查詢非常非常慢,超過 80 秒:

SELECT T1.id, T3.value
FROM first AS T1
JOIN second AS T3 ON T3.id IN (SELECT TOP 1 T2.id
                               FROM second AS T2 WITH(INDEX(IX_second))
                               WHERE T2.id = T1.id 
                                 AND T2.b = 1 
                                 AND T2.c = 0 
                                 AND T2.d = 0 
                                 AND T2.e = 0
                               ORDER BY T2.id, T2.b, T2.c, T2.d, T2.e, T2.timestamp DESC)
 WHERE T1.id = 21

為什么這個查詢會花這么長時間,我該如何讓它更快?


編輯:這是計划,更改了一些表和字段名稱以保護無辜者:) brentozar.com/pastetheplan/?id=rJYBSfwws

一切都取決於 DBMS 計算數據的方式。 但在這種情況下,將要處理 53M (T1 X T3) 次。 如果索引不是用值構建的(b,c,d,e ...),每次都會進行排序,反向,查詢以及可能與源表的一些連接。

我不明白你的查詢邏輯。 為什么不只使用一個連接...

SELECT T1.id, T3.value
  FROM first AS T1
  JOIN second AS T2 ON T1.id = T2.id 
 WHERE T1.id = 21 
  AND T2.b = 1 AND T2.c = 0 AND T2.d = 0 AND T2.e = 0

這看起來與上面的結果相同。

IN()語句中使用子查詢在語法上是可以的,但我不推薦它,因為它們是管理表之間 JOIN 的緩慢方式。

按照其他人的建議,使用臨時表 在我看來,即使是 CTE() 也至少是代碼的更簡潔版本並且更容易理解。 您還需要研究您的執行計划。

我沒有測試過這個,但嘗試類似的東西:

    SELECT TOP 1 T2.id
    INTO #tblTEMP1
    FROM second AS T2 
    WHERE T2.b = 1 
      AND T2.c = 0 
      AND T2.d = 0 
      AND T2.e = 0
    ORDER BY T2.id, T2.timestamp DESC
..
..
    SELECT T1.id, T3.value
    FROM first AS T1
    INNER JOIN #tblTEMP1 AS t ON t.ID = t1.ID
    INNER JOIN second AS T3 ON T3.id = t.ID
    WHERE T1.id = 21

我敢打賭這會更快,但可能沒有您預期的那么快。

同樣,您需要研究每個案例的執行計划並確定確切的瓶頸並在必要時放置INDEXes

這看起來像是可以使用CROSS APPLY的情況。 這允許TOP 1ORDER BY ,但會避免對second表的雙重引用。

嘗試:

SELECT T1.id, T3.value
FROM first AS T1
CROSS APPLY (
    SELECT TOP 1 T2.*
    FROM second AS T2 --WITH(INDEX(IX_second))
    WHERE T2.id = T1.id 
    AND T2.b = 1 
    AND T2.c = 0 
    AND T2.d = 0 
    AND T2.e = 0
    ORDER BY T2.id, T2.b, T2.c, T2.d, T2.e, T2.timestamp DESC
) T3
WHERE T1.id = 21

如果IX_secondsecond(id)上的索引,則 SQL 服務器查詢優化器很可能會 select 該索引而不需要索引提示。

只是為了檢查:你確定你的意思是T2.id = T1.id而不是像T2.first_id = T1.id這樣的東西嗎?

請注意:由於T2.id, T2.b, T2.c, T2.d, T2.e都將固定在CROSS APPLY結果中,因此您可以將它們從ORDER BY子句中刪除。

附錄:根據您發布的執行計划中的查詢,以上內容等同於:

SELECT *
FROM Event_Item AS ei
CROSS APPLY (
    SELECT TOP 1 eisp1.*
    FROM Event_Item_Spread AS eisp1
        -- WITH(INDEX(IX_Event_Item_Spread__event_item__sportsbook__period__ingame__alt__timestamp_desc))
    WHERE eisp1.event_item_id = ei.id
      AND eisp1.sportsbook_id = 1
      AND eisp1.period = 0
      AND eisp1.in_game = 0
      AND eisp1.alt = 0
    ORDER BY eisp1.timestamp DESC
) AS eisp
WHERE ei.id = 39604314

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM