考慮下面的查詢:優化SQL查詢,以避免全表掃描
SELECT * FROM Transactions
WHERE day(Stamp - interval 3 hour) = 1;
在交易表中的郵票列是TIMESTAMP和有它的索引。 如何更改此查詢以避免全表掃描? (即使用郵票以外的天()函數)
謝謝!
考慮下面的查詢:優化SQL查詢,以避免全表掃描
SELECT * FROM Transactions
WHERE day(Stamp - interval 3 hour) = 1;
在交易表中的郵票列是TIMESTAMP和有它的索引。 如何更改此查詢以避免全表掃描? (即使用郵票以外的天()函數)
謝謝!
如果目標僅僅是避免全表掃描,你必須爲交易主鍵(說叫PK),考慮增加覆蓋指數
ALTER TABLE Transactions ADD INDEX cover_1 (PK, Stamp)
然後
SELECT * FROM Transactions WHERE PK IN (SELECT PK FROM Transactions
WHERE day(Stamp - interval 3 hour) = 1
)
該查詢應不使用全表掃描(但是優化器可以決定使用全掃描,如果表格中的行數很少或者出於任何其他統計原因:))
更好的方式ma y是使用臨時表而不是子查詢。
分別計算你所需的郵票值運行您主查詢之前,即
步驟1 - 計算期望印記值
第2步 - 運行查詢,其中郵票>(計算值)
因爲在步驟2中沒有計算,您應該可以使用您的索引。
你可以經常重寫函數,所以你看起來像WHERE Stamp=XXXX
,而XXXX是一些表達式。您可以爲每個月創建一系列BETWEEN語句,WHERE Stamp BETWEEN timestamp('2010-01-01 00:00:00') AND timestamp ('2010-01-01 23:59:59') OR Stamp BETWEEN ...
,但我不確定在這種情況下會使用索引。我會按照@petr的建議創建一個月份的那一天。
如果我理解正確,你基本上想要返回郵票落在每個月的第一個(減去3小時)的所有行?如果(這是一個很大的話),你有一個固定的窗口,比如最近6個月,你可以列舉6個範圍測試。但是,我仍然不確定索引訪問會更快。
select *
from transactions
where stamp between timestamp '2010-06-01 03:00:00' and timestamp '2010-06-02 02:59:59'
or stamp between timestamp '2010-07-01 03:00:00' and timestamp '2010-07-02 02:59:59'
or stamp between timestamp '2010-08-01 03:00:00' and timestamp '2010-08-02 02:59:59'
or stamp between timestamp '2010-09-01 03:00:00' and timestamp '2010-09-02 02:59:59'
or stamp between timestamp '2010-10-01 03:00:00' and timestamp '2010-10-02 02:59:59'
or stamp between timestamp '2010-11-01 03:00:00' and timestamp '2010-11-02 02:59:59'
or stamp between timestamp '2010-12-01 03:00:00' and timestamp '2010-12-02 02:59:59';
注意!我不確定時間戳的毫秒部分是如何工作的。您可能需要相應地填充它。
爲了避免IN子句以及爲MyISAM或InnoDB創建它,稍加修改petr的回答。
對於MyISAM
ALTER TABLE Transactions ADD INDEX cover_1 (PK, Stamp)
或者,InnoDB的,其中PK是隱含在每一個指標,
ALTER TABLE Transactions ADD INDEX Stamp (Stamp)
然後
SELECT *
FROM Transactions LEFT JOIN
(
SELECT PK
FROM Transactions
WHERE DAYOFMONTH(Stamp - interval 3 hour) = 1
) a ON Transactions.PK=a.PK
子查詢將有一個索引只執行,並且外部查詢將只從a.PK通過的表中提取行。
我不是要求「功能索引」 - 它們不存在。 相反,我想轉換這個查詢以相同的方式,你可以將「SELECT * FROM table WHERE sqrt(column)= 2」轉換爲「SELECT * FROM table WHERE column = 4」 – emx 2010-12-02 13:15:34