2013-03-21 64 views
1

我正在重寫一箇舊的遺留系統。它有一個叫做checkExisting()的功能。舊的系統使用查詢從MSSQL數據庫,這樣提取的對象(與ADO DB):SQL Union一切都太慢

SELECT ObjectId, Name..... 
FROM tblRegisteredIncludes 
WHERE UPPER("Name") IN ('PROGA.H', 'PROGB.H'............... list) 

有喜歡tblRegisteredIncludes很多表,但SQLS由表名進行分組,並使用與列表中的IN子句對象名稱。

由於SQL Server在一次掃描中收集所有對象,並且表中有Name列的索引,因此執行速度適當。

但是,在新系統中,我不能使用相同的SQL,因爲WHERE條件更復雜。它也使用一個Source字段,有時還會使用其他字段。我有一個較大的數目單個SQL查詢:

SELECT ObjectId, Name..... FROM tblRegisteredIncludes 
WHERE UPPER("Name") = 'PROGA.H' AND UPPER("Source") = "..." 

SELECT ObjectId, Name..... FROM tblRegisteredIncludes 
WHERE UPPER("Name") = ('PROGB.H') AND UPPER("Source") = "..." 

我已經有超過(Name,Source)一個綜合指數更換名稱指數在tblRegisteredIncludes表。

我已經預料到即使如此,總SQL執行速度稍慢,但不超過15-20%。相反,它要慢得多,有時高達100%。我試着使用UNION ALL在一個大的SQL查詢SQL後結合:

SELECT ObjectId, Name..... FROM tblRegisteredIncludes 
WHERE UPPER("Name") = 'PROGA.H' AND UPPER("Source") = "..." 
UNION ALL 
SELECT ObjectId, Name..... FROM tblRegisteredIncludes 
WHERE UPPER("Name") = ('PROGB.H') AND UPPER("Source") = "..." 

再後來pocessing所產生的ADO記錄數據庫,但它更慢!

我需要知道是否有一些有效的方法來更快地執行這些查詢?使用IN子句和名稱列表時,我需要達到與舊案例類似的性能。我可以提供執行計劃。

+1

我希望看到執行計劃。你爲什麼要用'upper'?您是否檢查過排序規則是否區分大小寫? – 2013-03-21 12:17:00

+0

您可以詳細說明「我不能使用相同的SQL,因爲WHERE條件更復雜」。在您給出的示例中,沒有理由需要將查詢分開。 – GarethD 2013-03-21 12:25:49

+1

你真的需要UPPER嗎?這種情況很少使用區分大小寫的排序規則。使用UPPER會破壞你的查詢計劃,因爲這個函數對於SQL Server來說是不透明的 - 它不知道該函數做了什麼,所以它不會使用索引並執行表掃描。 – TToni 2013-03-21 12:32:12

回答

0

從你所描述的情況來看,我認爲表中有很多行,在這種情況下,它幾乎肯定是導致速度問題的UPPER,因爲這意味着它無法正確使用你所附帶的索引正確設置。數據是否真的區分大小寫? - 檢查數據庫設置,默認情況下通常不是在這種情況下,您可以刪除UPPER。

如果區分大小寫,那麼如果存儲名稱的大小寫一致,那麼仍然可以刪除Upper並只使用一致的大寫/小寫字母名稱,例如Name ='ProgB.H'

+0

非常感謝您的答覆。 – 2013-03-21 15:04:00

+0

非常感謝您的回覆。整個數據庫區分大小寫。是的,它可以包含非常多的行數,但即使只有很少的行數,我也可以看到很大的延遲。如果使用UPPER(),我如何檢查我的複合索引是否工作?該索引定義在兩列或三列,在這種情況下 - 名稱(ASC),來源(ASC)。是否存在複合索引的某些設置,使其明確區分大小寫,並使用f UPPER? – 2013-03-21 15:09:26

+0

只是不可能正確使用索引,因爲它是區分大小寫的順序,所以實際上它必須對錶進行掃描並將每個名稱轉換爲大寫以進行比較。正如我所說,如果可以保證表中的每個名稱在使用案例時保持一致,仍然可以刪除UPPER。或者你可以重新命名它們以保持一致?這裏是一個鏈接來查看exceution計劃http://msdn.microsoft.com/en-us/library/ms178071(v=sql.105).aspx – 2013-03-21 15:24:25

2

union all版本中,每個子查詢都會導致對錶進行單獨掃描。

你應該使用or條件帶來的所有行:

SELECT ObjectId, Name..... 
FROM tblRegisteredIncludes 
WHERE (UPPER("Name") = 'PROGA.H' AND UPPER("Source") = "...") or 
     (UPPER("Name") = ('PROGB.H') AND UPPER("Source") = "...") or 
     . . . 

如果你有一個情況,所有的比較都是在NameSource,我建議建立一個表上即時使用CTE:

with toinclude as (
    select 'PROGA.H' as name, 'SOURCE' as source union all 
    select . . . 
) 
select ri.ObjectId, ri.Name 
from tblRegisteredIncludes join 
    toinclude 
    on ri.name = toinclude.name and ri.source = toinclude.source 

你可以離開了toupper()除非你是特別關注的是,您的實現或領域都覆蓋不區分大小寫b的默認ehavior。在where子句中使用函數通常會阻止使用索引。

+0

非常感謝您的答覆。我需要檢查性能,如果我只是將所有條件與ORs粘合在一起。從執行計劃中我可以看出,只有一次掃描就像使用IN子句一樣。而對於UNION ALL來說,有很多掃描。我認爲UNION ALL更聰明。我會衡量表現。非常愚蠢的是我第一次沒有那樣做。我唯一擔心的是WHERE可能會變得太長,SQL解析器可能會延遲。感謝關於臨時表的建議,但我正在從幾個表中收集數據,這可能會導致性能下降。 – 2013-03-21 15:18:20