簡體   English   中英

優化SQL查詢以避免全表掃描

[英]Optimizing a SQL query to avoid full table scan

請考慮以下查詢:

SELECT * FROM Transactions
WHERE day(Stamp - interval 3 hour) = 1;

Transactions表中的Stamp列是TIMESTAMP,並且有一個索引。 我怎樣才能更改此查詢以避免全表掃描? (即在day()函數之外使用Stamp

謝謝!

我就是這樣做的:

添加一些額外的字段:YEAR,MONTH,DAY甚至HOUR,MINUTE,具體取決於您期望的流量。 然后構建一個觸發器來填充額外的字段,可以提前減去3小時的間隔。 最后在額外字段上構建一些索引。

如果目標只是為了避免全表掃描並且您有一個PRIMARY KEY(比如命名為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
 )

此查詢不應使用全表掃描(但是,如果表中的行數很小或者出於其他任何統計原因,優化程序可能決定使用完全掃描:))

更好的方法可能是使用臨時表而不是子查詢。

你經常可以重寫這個函數,所以你有一些看起來像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建議的那樣。

在運行主查詢之前單獨計算所需的Stamp值,即

第1步 - 計算所需的Stamp值

第2步 - 運行查詢,其中Stamp>(計算值)

由於步驟2中沒有計算,您應該能夠使用索引。

如果我理解正確的話,你基本上想要返回每個月郵票落在第一行的所有行(減去3小時)? 如果(這是一個很大的if),你有一個固定的窗口,比如說最近的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';

NB! 我不確定時間戳的毫秒部分是如何工作的。 您可能需要相應地填充它。

重新設計petr的答案以避免使用IN子句,並將其用於MyISAM或InnoDB。

對於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通過的表中提取行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM