2011-11-30 60 views
1

哪種方法可以在SQL Server上檢查當前月份的事件?爲什麼?在表SQL - 適用於當前月份的「where」子句

1)WHERE (DATEDIFF(month, EventTime, GETDATE())=0))

2)WHERE (YEAR(EventTime) = YEAR(GETDATE()) AND MONTH(EventTime) = MONTH(GETDATE()))

日期格式是即EventTime: 2011-11-30 15:68:25.000

+0

注意:數據類型DATETIME等沒有這種格式。這只是用來在屏幕上表示它們的格式,因爲我們人類不喜歡讀二進制文件等等。但是,如果它們實際上作爲字符串(NVARCHAR等)存儲在表中,則格式很重要,而且這個將嚴重打擊業績。 – MatBailie

+0

@Dems啊,不,這是一個日期時間格式,不是varchar,不用擔心:) – yosh

回答

7

我無法使用探查器訪問SQL Server,因此我實際上無法提供詳細的答案。

問題基本上是關於哪一個允許最少的計算和最有效的索引使用。

使用字符串操作的變量具有最高的計算負載,並且根本不使用索引。所以我會跳過這些。這留下了四種常見的表達方式...

SELECT * FROM date_sargable 
WHERE YEAR(value) = YEAR (getDate()) 
    AND MONTH(value) = MONTH(getDate()) 
; 

SELECT * FROM date_sargable 
WHERE DATEDIFF(MONTH, value, getDate()) = 0 
; 

SELECT * FROM date_sargable 
WHERE DATEDIFF(MONTH, 0, value) = DATEDIFF(MONTH, 0, getDate()) 
; 


SELECT * FROM date_sargable 
WHERE value >= DATEADD(MONTH, DATEDIFF(MONTH, 0, getDate()) , 0) 
    AND value < DATEADD(MONTH, DATEDIFF(MONTH, 0, getDate()) + 1, 0) 
; 

前三個使用INDEX SCAN,但最後一個使用INDEX SEEK。不同之處在於,查詢的格式允許優化器知道您想要特定範圍的數據,它在索引的一個塊中彼此相鄰,並且很容易找到該塊。

如果在查看執行計劃時,在一個版本中看到SEEK,而在另一個版本中看到SCAN,則更有可能從SEEK中受益。

+0

謝謝。所以簡單來說,這是一個BETWEEN條件的問題?不是比較每個記錄,而是爲了獲得一個範圍? – yosh

+0

BETWEEN是'> ='AND'<='。我更喜歡使用'> ='AND'<'。那是因爲我不必在乎數據是否存儲到一天,幾分鐘,幾毫秒等等。無論準確度如何,它都可以工作。但除此之外,是的,範圍通常在我的經驗中表現最好。 – MatBailie

+0

謝謝!幫助很多。 – yosh

1

在邏輯上,它們兩者都是。然而,我認爲第一個更簡單(一個條件而不是兩個),更容易理解並且更可能是可控的 - 所以我建議使用那個。

4

將連續期間的查詢寫爲明確的範圍條件。

http://use-the-index-luke.com/sql/where-clause/obfuscation/dates

因此,使用這樣的:

WHERE EventTime between <begin-of-month> and <end-of-month> 

示例代碼可在同一頁面上,雖然這樣季報過濾:

http://use-the-index-luke.com/sql/where-clause/obfuscation/dates?dbtype=sqlserver#sample_quarter_begin_end

爲什麼?使索引變得容易。

+0

我不明白這是怎麼使事情變得更簡單。如果遵循這個例子,sql server需要執行4個查詢,而不僅僅是一個:執行quarter_begin兩次,quarter_end一次,最後執行c的實際查詢。雖然我沒有足夠的數據和可能的知識來正確地測試,但我會懷疑這實際上比OP提供的任何解決方案都要慢。除了速度問題之外 - 它確實使整個查詢變得更加複雜。 –

+0

@Sascha Hennig - 函數(quater_end/begin)僅在實際查詢開始之前執行一次。如果您願意,也可以在應用程序中計算邊界日期(四捨五入結束/開始)。這並沒有帶來真正的性能差異。它使得索引變得更容易,因爲查詢可以在EventTime上使用直接索引,反過來,它將優於任何其他建議的變體。 –

+0

約定:計算範圍的標量常量可能會使用「很多」文本,但幾乎不會使用任何查詢成本。數據庫中最大的成本通常是從磁盤讀取數據,這種方法可以確保讀取磁盤的最小數量,從而將冗餘讀取數量減少到接近於0(SEEKing)。替代品有許多冗餘讀取(SCANing)。 – MatBailie

1

如果你對此列的索引,那麼這兩個計算,因爲你沒有使用什麼列索引,但只有該指數的一部分

WHERE (DATEDIFF(month, EventTime, GETDATE())=0)) 
WHERE (YEAR(EventTime) = YEAR(GETDATE()) AND MONTH(EventTime) = MONTH(GETDATE())) 

你是多大繞過指數使用這樣的事情

WHERE EventTime BETWEEN Cast (DATEADD(dd,-(DAY(GetDate())-1),GetDate()) as Date) 
       AND Cast (DATEADD(dd,-(DAY(DATEADD(mm,1,GetDate()))),DATEADD(mm,1,GetDate())) as Date) 

更好您還可以使用與>=<=同一概念的日期

0

一個提示使用to_char功能非常簡單,請看:

在日期例如:

2011-11-30 15:68:25.000

,你可以這樣做:

to_char(your_field,'MM')= 11

或系統日期的當前月份:

TO_CHAR(SYSDATE, 'MM')= 11

一個細節,TO_CHAR funcion由SQL語言支載,而不是由一個特定數據庫。