Mysql
使用索引日期時間列的 MySQL 性能問題
我現在嘗試解決以下問題大約一個小時,但仍然沒有進一步解決。
好的,我有一張桌子(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)
我有三個建議
建議#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
試一試 !!!