5

次のクエリについて考えてみます。

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

TransactionsテーブルのStamp列はTIMESTAMPであり、インデックスがあります。全表スキャンを回避するようにこのクエリを変更するにはどうすればよいですか?(つまり、 day()関数の外でStampを使用する)

ありがとう!

4

6 に答える 6

8

これは私がそれを行う方法です:

予想されるトラフィックに応じて、YEAR、MONTH、DAY、または HOUR、MINUTE などの追加フィールドを追加します。次に、事前に 3 時間の間隔を差し引いて、追加のフィールドに入力するトリガーを作成します。最後に、余分なフィールドにインデックスを作成します。

于 2010-12-02T12:05:18.647 に答える
1

目的が完全なテーブル スキャンを回避することだけであり、トランザクション用の 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
 )

このクエリでは、フル テーブル スキャンを使用しないでください (ただし、オプティマイザは、テーブル内の行数が少ない場合、またはその他の統計上の理由でフル スキャンを使用することを決定する場合があります:))

より良い方法は、サブクエリの代わりに一時テーブルを使用することです。

于 2010-12-02T13:49:57.823 に答える
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 が示唆するように、月の日である列を作成します。

于 2010-12-02T13:59:38.673 に答える
0

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が通過したテーブルから行のみをプルします。

于 2010-12-02T17:04:12.713 に答える
0

私が正しく理解している場合、基本的には、各月の最初にスタンプが該当するすべての行を返したいですか (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';

注意!タイムスタンプのミリ秒部分がどのように機能するかわかりません。それに応じてパディングする必要があるかもしれません。

于 2010-12-02T15:24:53.967 に答える
0

メインクエリを実行する前に、目的のスタンプ値を個別に計算します。つまり、

ステップ 1 - 必要なスタンプ値を計算する

ステップ 2 - スタンプ > (計算値) のクエリを実行します。

ステップ 2 には計算がないため、インデックスを使用できるはずです。

于 2010-12-02T13:58:31.000 に答える