インデックス付き日時列を使用したMySQLパフォーマンスの問題


14

次の問題を約1時間解決しようとしましたが、それでも解決できませんでした。

さて、テーブルがあります(MyISAM):

+---------+-------------+------+-----+-------------------+----------------+
| Field   | Type        | Null | Key | Default           | Extra          |
+---------+-------------+------+-----+-------------------+----------------+
| id      | int(11)     | NO   | PRI | NULL              | auto_increment |
| http    | smallint(3) | YES  | MUL | 200               |                |
| elapsed | float(6,3)  | NO   |     | NULL              |                |
| cached  | tinyint(1)  | YES  |     | NULL              |                |
| ip      | int(11)     | NO   |     | NULL              |                |
| date    | timestamp   | NO   | MUL | CURRENT_TIMESTAMP |                |
+---------+-------------+------+-----+-------------------+----------------+

インデックスを気にしないでください、私は解決策を見つけようとして遊んでいます。さて、ここに私のクエリがあります。

SELECT http,
COUNT( http )  AS count 
FROM reqs
WHERE DATE(date) >= cast(date_sub(date(NOW()),interval 24 hour) as datetime)
GROUP BY http
ORDER BY count;

テーブルには着信Webリクエストに関する情報が保存されるため、かなり大きなデータベースになります。

+-----------+
| count(id) |
+-----------+
|    782412 |
+-----------+

id列が唯一の一意の識別子になるため、主キーを設定するより良い方法はありません。上記のクエリの実行には約0.6〜1.6秒かかります。

どのインデックスが賢明でしょうか?インデックス付けの日付によって「悪い」カーディナリティが得られるため、MySQLはインデックスを使用しません。httpは、20種類の値しか存在しないため、悪い選択でもあります。

助けてくれてありがとう!

更新1 ypercubeが示唆したように(http、date)にインデックスを追加しました:

mysql> CREATE INDEX httpDate ON reqs (http, date);

そして彼のクエリを使用しましたが、同様に悪いパフォーマンスを示しました。追加されたインデックス:

+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| reqs  |          0 | PRIMARY  |            1 | id          | A         |      798869 |     NULL | NULL   |      | BTREE      |         |
| reqs  |          1 | httpDate |            1 | http        | A         |          19 |     NULL | NULL   | YES  | BTREE      |         |
| reqs  |          1 | httpDate |            2 | date        | A         |       99858 |     NULL | NULL   |      | BTREE      |         |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+

説明

+----+--------------------+-------+-------+---------------+----------+---------+------+-------+-----------------------------------------------------------+
| id | select_type        | table | type  | possible_keys | key      | key_len | ref  | rows  | Extra                                                     |
+----+--------------------+-------+-------+---------------+----------+---------+------+-------+-----------------------------------------------------------+
|  1 | PRIMARY            | r     | range | NULL          | httpDate | 3       | NULL |    20 | Using index for group-by; Using temporary; Using filesort |
|  2 | DEPENDENT SUBQUERY | ri    | ref   | httpDate      | httpDate | 3       | func | 41768 | Using where; Using index                                  |
+----+--------------------+-------+-------+---------------+----------+---------+------+-------+-----------------------------------------------------------+

MySQLサーバーのバージョン:

mysql> SHOW VARIABLES LIKE "%version%";
+-------------------------+---------------------+
| Variable_name           | Value               |
+-------------------------+---------------------+
| protocol_version        | 10                  |
| version                 | 5.1.73              |
| version_comment         | Source distribution |
| version_compile_machine | x86_64              |
| version_compile_os      | redhat-linux-gnu    |
+-------------------------+---------------------+
5 rows in set (0.00 sec)

mysqlバージョンとテーブルのエンジンも追加できますか?(MyISAMテーブルまたはInnoDBテーブル)
ypercubeᵀᴹ

MyISAMおよび5.1.73-詳細はすべてポストにあります。
ロビンヘラー14

http列がNULL値を許可することと関係があるのではないかと思います。時間があれば明日調査します。
ypercubeᵀᴹ

私は、httpカラムがヌル可能であることと関係があるのではないかと心配しています。時間があれば明日調査します。あなたは(を除いて同じテーブルを作成することでテストすることができhttp NOT NULLます(http NULLもちろんで行を除く。))及びそれにすべてのデータをコピーする
ypercubeᵀᴹ

これをNOT NULLに変更すると(完全に可能ですが、テーブルを作成するときにあまり気にしませんでした)、クエリ(私のクエリ)のパフォーマンスが約1〜1.6秒に向上しました。これまでの努力に感謝します。
ロビンヘラー14

回答:


10

私は3つの提案があります

提案#1:クエリを書き換えます

次のようにクエリを書き換える必要があります

SELECT http,
COUNT( http )  AS count 
FROM reqs
WHERE date >= ( DATE(NOW() - INTERVAL 1 DAY) + INTERVAL 0 SECOND )
GROUP BY http
ORDER BY count;

または

SELECT * FROM
(
    SELECT http,
    COUNT( http )  AS count 
    FROM reqs
    WHERE date >= ( DATE(NOW() - INTERVAL 1 DAY) + INTERVAL 0 SECOND )
    GROUP BY http
) A ORDER BY count;

WHEREには、等号の両側に関数があってはなりません。等号の左側に日付があると、クエリオプティマイザーがそれに対してインデックスを使用しやすくなります。

提案#2:サポートインデックス

また、別のインデックスをお勧めします

ALTER TABLE reqs ADD INDEX date_http_ndx (date,http); -- not (http,date) 

dateエントリはすべてインデックス内で連続しているため、この列の順序をお勧めします。次に、クエリはのhttpギャップをスキップせずに値を収集しますhttp

提案#3:より大きなキーバッファー(オプション)

MyISAMはインデックスキャッシングのみを使用します。クエリは.MYDファイルに触れてはならないため、わずかに大きいMyISAMキーバッファーを使用する必要があります。

256Mに設定するには

SET @newsize = 1024 * 1024 * 256;
SET GLOBAL key_buffer_size = @newsize;

次に、それを my.cnf

[mysqld]
key_buffer_size = 256M

MySQLの再起動は不要

試してみる !!!


あなたがくれたクエリを試しました。#1は、他の提案または私自身の提案とほぼ同じくらいうまく機能しましたが、2番目の提案は実際にはより悪く機能しました。支持指数についても同じこと-パフォーマンスを約75%低下させます。私は今より大きなキーバッファを試してみるつもりです、とにかくありがとう!
ロビンヘラー14

キーバッファを大きくするとパフォーマンスは多少向上しましたが、問題は解決しませんでしたが、私はあなたの答えを受け入れました。これがすべての最高のソリューションであるため、これを閉じます。ありがとうございました!
ロビンヘラー14

提案#2を機能させるには、クエリに「USE INDEX」または「FORCE INDEX」を追加する必要がある場合があります。少なくとも、そのようなインデックスを作成した後、クエリを高速化するために行う必要があります。
ヨハノフィエラ

-2

日付列タイプを整数に変更します。日付を整数のUnix日付として保存します。タイムスタンプはintよりもはるかに大きいです。あなたはそれからいくつかの強打を得るでしょう。


2
冗談ですか?どちらINTTIMESTAMP4バイトを必要としています。
ypercubeᵀᴹ

2
日付またはタイムスタンプを整数として保存すると、すべての日時関数が失われることは言うまでもありません。
ypercubeᵀᴹ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.