2009-11-10 40 views
19

我想寫一個簡單地返回1或0的查詢,具體取決於是否會有結果。檢查SQL查詢是否會返回結果的有效方法

我想利用這個

IF EXISTS(
     select * from myTable 
     where id=7 and rowInsertDate BETWEEN '01/01/2009' AND GETDATE() 
) 
SELECT 1 
ELSE 
SELECT 0 

是一般的前提。

最終的結果實際上是一個更爲複雜的查詢,以一對多的參數,並建立了串並執行使用sp_executesql

我的問題是,您說的「計數」將返回376986,並採取4秒計算。一旦找到滿足條件的一行,就使用IF EXISTS停止。

我決定使用IF EXISTS或只是查詢@@ ROWCOUNT並查看它是否大於零。

我確實嘗試過一些測試,兩者都以相同的速度運行,但是在兩年內有更多數據可能使用時,IF EXISTS將會成爲性能增益?

謝謝

回答

7

如果EXISTS應該更有效率,因爲它被優化爲一找到第一行就停下來。這是我總是會做這種檢查,而不是使用COUNT()。

對於性能比較,只是確保你被(唯一的非生產數據庫服務器)每次測試之前清除下來的數據,並執行計劃緩存相當測試:

DBCC FREEPROCCACHE 
DBCC DROPCLEANBUFFERS 
+0

這取決於DBMS的查詢優化器。如果他的測試顯示IF EXISTS和COUNT都需要4秒,那麼IF EXISTS可能不會優化。 –

+0

現在結果是一樣的,但我對未來的查詢更多。隨着行數增加,我想知道計數性能是否會變慢。有人建議,因爲無論如何都要分析表格並且執行計數仍然相當快。我越來越傾向於IF EXISTS。 – Robert

+0

我會比較兩個,清理緩存,檢查持續時間,cpu和通過SQL事件探查器讀取,並期望EXISTS不僅在SQL Server中執行得更好,而且在數據量增長時也可以更好地擴展。對於少量數據,不會有太大區別,但可擴展性非常重要。 – AdaTheDev

11

你有一個id和日期的索引?

也許你只是想:

select top 1 1 from myTable where id=7 and rowInsertDate > '01/01/2009' 

注意:如果存在數據將返回1,或任何其他方式。

另一編輯。如果沒有數據,這將不會返回值爲null的行,而不會返回任何行。更像是更具象徵意義上的空值。

+0

這給查詢優化器提供了更多的線索,我期望它更快。 –

+0

Clever =解決方案。 –

+0

確保獲得適當的平臺依賴限制條款。 top 1或limit 1等。 – Kevin

2

如果您不需要376986行只是想知道是否存在某些東西,那麼IF EXISTS更有意義。 此外,另一個有用的位是要求索引列(主鍵)而不是*,因爲您不關心實際數據。

+0

謝謝我一定會問我的結果只有1列,因爲我實際上並不想要結果。 – Robert

10

這是最快的,我可以得到我的項目:

SELECT CASE WHEN EXISTS (
    select top 1 1 
    from myTable 
    where id=7 
    and rowInsertDate BETWEEN '01/01/2009' AND GETDATE() 
) THEN 1 ELSE 0 END AS AnyData 
+0

這是我將要使用的一般前提。謝謝 – Robert

0

首先,你應該嘗試,你認爲你(或你的繼任者)可能不得不應對接到虛了一個數據庫包含儘可能多的數據在兩年內。那麼你的測試將會更有成效。

如果EXISTS()會更快,因爲數據庫引擎只需找到符合條件的第一個匹配記錄。當然,通過適當的索引,它當然會更快。

另一個提示,不要使用*,因爲你實際上並不需要檢索列。

IF EXISTS(select 1 from myTable where id=7 and rowInsertDate BETWEEN '01/01/2009' AND GETDATE()) 

...應該(從我讀過的)工作更快一點。

+1

如果您使用SELECT * ...並不重要,EXISTS已針對此進行了優化。沒什麼區別。 – AdaTheDev

2

我只想寫這種方式:

IF EXISTS(
     SELECT 0 FROM myTable 
     WHERE id=7 and rowInsertDate BETWEEN '01/01/2009' AND GETDATE() 
) 
SELECT 1 
ELSE 
SELECT 0 

這樣,你不返回任何數據只是檢查的條件。我發現這個查詢結構超快。

1

最終的結果實際上將是 更爲複雜的查詢,取一個 許多參數並建立 了串並執行使用sp_executesql

我想你,至少需要完全FROM,JOIN和WHERE語法,否則你的實際查詢可能會發現nothiong(例如,通過添加不在原始IF EXISTS查詢中的INNER JOIN,結果不被滿足)。

如果你想要解決這個問題,你可能想讓PK進入某種「Batch ID Holding Table」,這樣你就可以引用查詢中第二個「Presentation」部分的PK。

如果您獲得376,986個結果,您打算如何處理?如果您要在屏幕上向用戶展示他們,使用某種分頁方式,然後在「批量ID保持表」中顯示結果可能會有所幫助(但顯然,對添加的數據進行任何添加/刪除操作將會分散顯示)。

或者,如果您要使用分頁,只需使用TOP/LIMIT/SET ROWCOUNT將結果限制爲第一頁已滿(確保您有ORDER BY,以便序列可重複),然後整理當用戶按下NEXT-PAGE按鈕時我們要做什麼(我們通過NEXT-PAGE按鈕解決了這個問題,該按鈕包含顯示的最後一條記錄的PK,按照排序順序,以便下一頁可以從該點開始繼續)。

查詢優化器將根據SELECT列表執行不同的操作 - 因此詢問「IF EXISTS」後跟「SELECT Col1,COl2,... FROM ...」可能實際上意味着您運行完整查詢兩次,方式不同,採用不同的緩存數據和查詢計劃,因此整體可能更應變的服務器上,並導致用戶等待更長的時間,不僅僅是歌廳第一頁/ 100行等

SQL服務器將緩存sp_ExecuteSQL的查詢計劃,但請確保您參數化查詢,以便緩存的計劃在可能的情況下得到重新分配

+0

是的,我會明確地參數化生成的查詢並將我的參數傳遞到sp_executesql。我記得第一次看到我不得不笑。現在我很滿意:) – Robert

0

我認爲Alex Bagnolini的回答是正確的。該系統不會讓我評論他的答案(新的acct)。我所做的唯一修改是將第二個1更改爲id。

有時減少項目部分中的列表(這是列列表)允許數據庫引擎僅命中索引,而不是表,因此速度更快。這當然取決於你的數據庫引擎和索引結構/大小。(所有rowInsertDate日期應< GETDATE(),所以可以跳過該比較)

SELECT CASE WHEN EXISTS( 從myTable的 其中id = 7 和rowInsertDate> '01/01/2009選擇頂部1的id ' )THEN 1 ELSE 0 END AS AnyData