Sql-Server

SQL Select 執行時間過長

  • June 29, 2011

這是從臨時表中進行的簡單選擇,在其主鍵上左連接現有表,兩個子選擇使用 top 1 引用連接表。

在程式碼中:

SELECT
   TempTable.Col1,
   TempTable.Col2,
   TempTable.Col3,
   JoinedTable.Col1,
   JoinedTable.Col2,
   (
       SELECT TOP 1
           ThirdTable.Col1 -- Which is ThirdTable's Primary Key
       FROM
           ThirdTable
       WHERE
           ThirdTable.SomeColumn = JoinedTable.SomeColumn
   ) as ThirdTableColumn1,
   (
       SELECT TOP 1
           ThirdTable.Col1 -- Which is also ThirdTable's Primary Key
       FROM
           ThirdTable
       WHERE
           ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
   ) as ThirdTableColumn2,
FROM
   #TempTable as TempTable
LEFT JOIN
   JoinedTable
ON (TempTable.PKColumn1 = JoinedTable.PKColumn1 AND 
   TempTable.PKColumn2 = JoinedTable.PKColumn2)
WHERE
   JoinedTable.WhereColumn IN  (1, 3)

這是我的查詢的精確副本。

如果我刪除兩個子選擇,它執行得很好而且很快。通過兩個子選擇,我每秒得到大約 100 條記錄,這對於這個查詢來說非常慢,因為它應該返回近一百萬條記錄。

我檢查了每個表是否都有主鍵,它們都有。它們都有重要列的索引和統計資訊,例如那些 WHERE 子句中的那些,以及 JOIN 子句中的那些。唯一沒有定義主鍵也沒有索引的表是臨時表,但這也不是問題,因為它不是與慢速子選擇相關的表,而且正如我所提到的,沒有子選擇它執行得很好。

沒有這些TOP 1,它會返回多個結果,並引發錯誤。

幫助,有人嗎?

編輯

所以執行計劃告訴我我缺少一個索引。我已經創建了它,並重新創建了一些其他索引。過了一會兒,執行計劃正在使用它們,現在查詢執行得很快。唯一的問題是我沒有成功地在另一台伺服器上再次針對相同的查詢執行此操作。所以我的解決方案是提示 SQL Server 將使用哪個索引。

我認為在一百萬條記錄查詢中,您必須避免使用OUTER JOINS. 我建議你使用UNION ALL而不是LEFT JOIN. 只要我認為CROSS APPLY比select子句中的子查詢效率更高,我會修改Conard Frix寫的查詢,我認為是正確的。

現在:當我開始修改您的查詢時,我注意到您有一個 WHERE 子句說: JoinedTable.WhereColumn IN (1, 3)。在這種情況下,如果該欄位為 null,則條件將變為 false。那麼為什麼在過濾空值行時使用 LEFT JOIN 呢?只需替換LEFT JOINWith INNER JOIN,我保證它會變得更快。

關於指數:

請注意,當您在表格上有索引時,請說

table1(a int, b nvarchar)

你的索引是:

nonclustered index ix1 on table1(a)

你想做這樣的事情:

select a,b from table1
where a < 10

在您的索引中,您沒有包含該列b,那麼會發生什麼?

如果 sql-server 使用您的索引,則必須在索引中搜尋,稱為**“Index Seek”,然後參考主表獲取列b,稱為“Look Up”。此過程可能比掃描表本身花費更長的時間:“表掃描”**。

但是根據 sql-server 的統計資訊,在這種情況下,它可能根本不使用您的索引。

所以首先檢查Execution Plan是否使用了索引。

如果兩者都是或否,請更改您的索引以包含您選擇的所有列。像這樣說:

nonclustered index ix1 on table1(a) include(b)

在這種情況下,不需要查找,您的查詢將執行得更快。

引用自:https://dba.stackexchange.com/questions/3544