衆所周知,sql寫得怎麼樣,對於查詢效率的影響是頗大的。下面看一個比較普通的查詢:
假設一張表有event_date和event_time2個字段分別表示日期和時間,現在直接給你一個時間字符串,這個時間字符串是“日期+時間”的組合,現在需要按時間範圍過濾出一部分數據。如果你不轉彎的話,很有可能你會按照慣性思維使用concat(event_date, event_time)連接函數,如:
SELECT A, MAX(B) AS B,SUBSTR(CONCAT(event_date, event_time),1,12)AS tran_time
FROM tablename
WHERE SUBSTR(CONCAT(event_date, event_time),1,12) >= :start_time
AND SUBSTR(CONCAT(event_date, event_time),1,12) < :end_time
AND A = :A
GROUP BY A,tran_time
ORDER BY A,tran_time ASC
start_time和end_time是傳遞過來的由“日期+時間”組合成的字符串。
這是比較容易想到的傳統思維,但這種sql語句的查詢效率老低了。差不多查一次需要4.5s+, 因爲不僅僅需要用到max函數,還需按SUBSTR(CONCAT(event_date, event_time),1,12) 這個計算出來的字段group by,最主要的是在where語句裏,對2個時間的字段需要進行多重函數運算後看看那些記錄符合你所規定的時間範圍~~ 這樣,在不知不覺中,造成了全表掃描,效率極低,特別是在表中數據量比較大的時候。
我們已經知道,如果一張表是數據量比較大的表,並且一般都用與於查詢時,索引的使用會給我們帶來極大的性能優化。考慮到使用索引,我們應該儘量避免where語句裏的字段不進行函數作用(因爲即使你對where下的字段建立了索引,但如果你對他們進行了函數運算,索引是失效的),所以我們考慮把它們儘量獨立開來。
基於上述思想,改正如下:
先對A, evnet_date和event_time三個字段建立索引。
SELECT A, MAX(B) AS B,SUBSTR(CONCAT(event_date, event_time),1,12)AS tran_time
FROM tablename
WHERE event_date >= :start_date AND event_time >= :start_time
AND event_date <= :end_date AND event_time < :end_time
AND A = :A
GROUP BY A,tran_time
ORDER BY A,tran_time ASC
可以看出我們把event_date和event_time的起止時間都“拆”開來了,所以只需在傳過來的起止時間字符串上截取響應的日期和時間字符串給sql語句即可。
測試檢查發現,2句sql查詢出的結果是一致的,說明他們是等效的。
改正之後,發現效率提升至0.05s左右,性能得到極大提升!!!
這句優化後的sql語句是突破了sql語句字段去適應外部傳過來的時間字符串,而是從sql優化的角度看,讓外部的條件去適應sql語句的查詢,這種思想我之前很少有,也算是一種思維的突破了!