web-dev-qa-db-ja.com

MySqlのDATETIMEフィールドの日付部分にインデックスを作成する方法

DATETIMEフィールドの日付部分にインデックスを作成するにはどうすればよいですか?

mysql> SHOW COLUMNS FROM transactionlist;
+-------------------+------------------+------+-----+---------+----------------+
| Field             | Type             | Null | Key | Default | Extra          |
+-------------------+------------------+------+-----+---------+----------------+
| TransactionNumber | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| WagerId           | int(11)          | YES  | MUL | 0       |                |
| TranNum           | int(11)          | YES  | MUL | 0       |                |
| TranDateTime      | datetime         | NO   |     | NULL    |                |
| Amount            | double           | YES  |     | 0       |                |
| Action            | smallint(6)      | YES  |     | 0       |                |
| Uid               | int(11)          | YES  |     | 1       |                |
| AuthId            | int(11)          | YES  |     | 1       |                |
+-------------------+------------------+------+-----+---------+----------------+
8 rows in set (0.00 sec)

TranDateTimeは、トランザクションの発生日時を保存するために使用されます

私のテーブルには1,000,000以上のレコードとステートメントがあります

SELECT * FROM transactionlist where date(TranDateTime) = '2008-08-17' 

長い時間がかかります。

編集:

なぜMySQLのDATETIMEを避けることができ、避けるべきか 」に関するこのブログ投稿をご覧ください。

65
Charles Faiga

正しく覚えていれば、関数を介して列を渡すため、テーブル全体のスキャンが実行されます。クエリオプティマイザーは関数の結果を実際に知ることができないため、MySQLはインデックスをバイパスして、すべての列に対して関数を素直に実行します。

私がすることは次のようなものです:

SELECT * FROM transactionlist 
WHERE TranDateTime BETWEEN '2008-08-17' AND '2008-08-17 23:59:59.999999';

これで、2008年8月17日に発生したすべてのことがわかります。

62
Michael Johnson

キュートに聞こえるつもりはありませんが、簡単な方法は、日付部分とそのインデックスのみを含む新しい列を追加することです。

11

日付部分だけにインデックスを作成することはできません。しなければならない理由はありますか?

日付部分だけにインデックスを作成できたとしても、オプティマイザーはおそらく上記のクエリにそれを使用しないでしょう。

あなたはそれを見つけると思う

SELECT * FROM transactionlist WHERE TranDateTime BETWEEN '2008-08-17' AND '2008-08-18'

効率的で、あなたが望むことをします。

9
MarkR

別のオプション( バージョンに関連5.7.3以上 )は、datetime列に基づいて生成列/仮想列を作成することです、それからインデックスを作成します。

CREATE TABLE `table` (
`my_datetime` datetime NOT NULL,
`my_date` varchar(12) GENERATED ALWAYS AS (DATE(`my_daetime`)) STORED,
KEY `my_idx` (`my_date`)
) ENGINE=InnoDB;
7
Liran Brimer

MySqlの詳細については知りませんが、日付フィールド全体をインデックス化するだけでは何が害になりますか?

次に検索するだけです:

 select * from translist 
     where TranDateTime > '2008-08-16 23:59:59'
        and TranDateTime < '2008-08-18 00:00:00'

インデックスがBツリーまたは他の妥当なものである場合、これらはすぐに見つかるはずです。

4
Clinton Pierce

Valeriy Kravchukは、MySQLサイトでこの問題に対する機能要求について、この方法を使用すると述べました。

「当面、文字列を使用して文字列としてDATETIME値を格納できます。最初のN文字のみがインデックス付けされます。MySQL5でトリガーを慎重に使用すると、この考えに基づいて合理的な堅牢なソリューションを作成できます。」

この列を追加するのは非常に簡単なルーチンを作成し、トリガーを使用してこの列の同期を維持できます。この文字列列のインデックスはかなり速いはずです。

2
Ray Jenkins

動作が非常に良い1つの優れたソリューションは、日時ではなくタイムスタンプを時刻として使用することです。 INTとして保存され、十分にインデックス付けされています。個人的には、トランザクションテーブルでこのような問題が発生しました。約100万件のレコードがあり、速度が大幅に低下しました。今では非常に高速に実行されます。

2
Valentin Rusk

datetime LIKE something%もインデックスをキャッチしません。

これを使用してください:WHERE datetime_field> = curdate();
それはインデックスをキャッチします、
and cover today:00:00:00 up to today:23:59:59
完了。

1
Dr. Tyrell

MySQLの詳細については知りませんが、日付フィールド全体をインデックス化するだけでは何が害になりますか?

値を取得するために関数を呼び出す必要があるため、*ツリー、ハッシュ、...に関数マジックを使用する場合はなくなります。ただし、先の結果がわからないため、テーブルを完全にスキャンする必要があります。

追加するものはありません。

たぶん、計算された(計算された?)インデックスのようなものを意味するかもしれません...しかし、今までのところ、これはIntersystemsCachéでしか見ていません。リレーショナルデータベース(AFAIK)に問題があるとは思わない。

私の意見では、良い解決策は次のとおりです(clintpの例を更新)。

SELECT * FROM translist 
WHERE TranDateTime >= '2008-08-17 00:00:00.0000'
  AND TranDateTime < '2008-08-18 00:00:00.0000'

私の意見では、00:00:00.0000を使用するか00:00を使用するかに違いはありません(通常、この形式で使用します)。

1
antonia007

「説明」とは何を言いますか? (EXPLAIN SELECT * FROM transactionlist where date(TranDateTime)= '2008-08-17')

Date()関数のためにインデックスを使用していない場合、範囲クエリは高速に実行されます。

SELECT * FROM transactionlist where TranDateTime> = '2008-08-17' AND TranDateTime <'2008-08-18'

0
nathan

関数に基づいてインデックスを作成するのではなく(mysqlで可能な場合)、where句で範囲比較を行います。何かのようなもの:

TranDateTime> '2008-08-17 00:00:00'およびTranDateTime <'2008-08-17 11:59:59')

これにより、DBはTranDateTimeのインデックス(1つありますよね?)を使用して選択を行います。

0
Justsalt

テーブルの変更がオプションである場合、または新しいテーブルを作成する場合は、それぞれのタイプの別々の列に日付と時刻を保存することを検討してください。キースペースをはるかに小さくし、ストレージを削減することでパフォーマンスを実現します(日時から派生した日付のみの列と比較して)。これにより、他の列の前であっても、複合キーでの使用が可能になります。

OPの場合:

+-------------------+------------------+------+-----+---------+----------------+
| Field             | Type             | Null | Key | Default | Extra          |
+-------------------+------------------+------+-----+---------+----------------+
| TransactionNumber | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| WagerId           | int(11)          | YES  | MUL | 0       |                |
| TranNum           | int(11)          | YES  | MUL | 0       |                |
| TranDate          | date             | NO   |     | NULL    |                |
| TranTime          | time             | NO   |     | NULL    |                |
| Amount            | double           | YES  |     | 0       |                |
| Action            | smallint(6)      | YES  |     | 0       |                |
| Uid               | int(11)          | YES  |     | 1       |                |
| AuthId            | int(11)          | YES  |     | 1       |                |
+-------------------+------------------+------+-----+---------+----------------+
0
Walf