次のクエリについて考えてみます。
SELECT * FROM Transactions
WHERE day(Stamp - interval 3 hour) = 1;
TransactionsテーブルのStamp列はTIMESTAMPであり、インデックスがあります。全表スキャンを回避するようにこのクエリを変更するにはどうすればよいですか?(つまり、 day()関数の外でStampを使用する)
ありがとう!
次のクエリについて考えてみます。
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 が示唆するように、月の日である列を作成します。
INT句を回避し、MyISAMまたはInnoDB用にするために、petrの回答を少し作り直しました。
MyISAMの場合
ALTER TABLE Transactions ADD INDEX cover_1 (PK, Stamp)
または、PKがすべてのインデックスに暗黙的に含まれているInnoDBの場合、
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が通過したテーブルから行のみをプルします。
私が正しく理解している場合、基本的には、各月の最初にスタンプが該当するすべての行を返したいですか (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';
注意!タイムスタンプのミリ秒部分がどのように機能するかわかりません。それに応じてパディングする必要があるかもしれません。
メインクエリを実行する前に、目的のスタンプ値を個別に計算します。つまり、
ステップ 1 - 必要なスタンプ値を計算する
ステップ 2 - スタンプ > (計算値) のクエリを実行します。
ステップ 2 には計算がないため、インデックスを使用できるはずです。