我有下一个结构的表statistics
:
+-------------------+----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+----------------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| created_at | datetime | YES | MUL | NULL | |
| year_in_tz | smallint(5) unsigned | YES | MUL | NULL | |
| month_in_tz | tinyint(3) unsigned | YES | MUL | NULL | |
+-------------------+----------------------+------+-----+---------+----------------+
使用created_at,year_in_tz,month_in_tz和on(year_in_tz,month_in_tz)上的键:
ALTER TABLE `statistics` ADD INDEX created_at (created_at);
alter table statistics add index year_in_tz (year_in_tz);
alter table statistics add index month_in_tz (month_in_tz);
alter table statistics add index year_month_in_tz(year_in_tz,month_in_tz);
一些查询示例......
mysql> SELECT COUNT(*) AS count_all, year_in_tz, month_in_tz
FROM `statistics`
GROUP BY year_in_tz, month_in_tz;
+-----------+------------+-------------+
| count_all | year_in_tz | month_in_tz |
+-----------+------------+-------------+
| 467890 | 2011 | 11 |
| 7339389 | 2011 | 12 |
+-----------+------------+-------------+
2 rows in set (5.04 sec)
mysql> describe SELECT COUNT(*) AS count_all, year_in_tz, month_in_tz FROM `statistics` GROUP BY year_in_tz, month_in_tz;
+----+-------------+--------------------+-------+---------------+------------------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------------+-------+---------------+------------------+---------+------+---------+-------------+
| 1 | SIMPLE | statistics | index | NULL | year_month_in_tz | 5 | NULL | 7797984 | Using index |
+----+-------------+--------------------+-------+---------------+------------------+---------+------+---------+-------------+
1 row in set (0.01 sec)
mysql> SELECT COUNT(*) AS count_all, year_in_tz, month_in_tz
FROM `statistics`
WHERE (created_at BETWEEN '2011-10-31 20:00:00' AND '2011-12-31 19:59:59')
GROUP BY year_in_tz, month_in_tz;
+-----------+------------+-------------+
| count_all | year_in_tz | month_in_tz |
+-----------+------------+-------------+
| 467890 | 2011 | 11 |
| 7339389 | 2011 | 12 |
+-----------+------------+-------------+
2 rows in set (1 min 33.46 sec)
mysql> describe SELECT COUNT(*) AS count_all, year_in_tz, month_in_tz FROM `statistics` WHERE (created_at BETWEEN '2011-10-31 20:00:00' AND '2011-12-31 19:59:59') GROUP BY year_in_tz, month_in_tz;
+----+-------------+--------------------+-------+---------------+------------------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------------+-------+---------------+------------------+---------+------+---------+-------------+
| 1 | SIMPLE | statistics | index | created_at | year_month_in_tz | 5 | NULL | 7797984 | Using where |
+----+-------------+--------------------+-------+---------------+------------------+---------+------+---------+-------------+
1 row in set (0.07 sec)
因此,如果我通过索引列对索引列+组使用where语句with子句,则速度极低。 也许有人知道如何改进上次查询以使其更快?
PS 在使用索引后,我发现(created_at,year_in_tz,month_in_tz)上的新索引使查询运行得更快,但我希望每个查询0-1秒,而不是10秒:
alter table lending_statistics add index created_at_with_year_and_month_in_tz (created_at,year_in_tz,month_in_tz);
mysql> describe SELECT COUNT(*) AS count_all, year_in_tz, month_in_tz FROM `statistics` WHERE (created_at BETWEEN '2011-10-31 20:00:00' AND '2011-12-31 19:59:59') GROUP BY year_in_tz, month_in_tz;
+----+-------------+--------------------+-------+-------------------------------------------------+--------------------------------------+---------+------+---------+-----------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------------+-------+-------------------------------------------------+--------------------------------------+---------+------+---------+-----------------------------------------------------------+
| 1 | SIMPLE | statistics | range | created_at,created_at_with_year_and_month_in_tz | created_at_with_year_and_month_in_tz | 9 | NULL | 3612208 | Using where; Using index; Using temporary; Using filesort |
+----+-------------+--------------------+-------+-------------------------------------------------+--------------------------------------+---------+------+---------+-----------------------------------------------------------+
1行(0.05秒)
mysql> SELECT COUNT(*) AS count_all, year_in_tz, month_in_tz FROM `lending_statistics` WHERE (created_at BETWEEN '2011-10-31 20:00:00' AND '2011-12-31 19:59:59') GROUP BY year_in_tz, month_in_tz;
+-----------+------------+-------------+
| count_all | year_in_tz | month_in_tz |
+-----------+------------+-------------+
| 467890 | 2011 | 11 |
| 7339389 | 2011 | 12 |
+-----------+------------+-------------+
2 rows in set (10.62 sec)
答案 0 :(得分:1)
将字段ID添加到索引created_at_with_year_and_month_in_tz,然后将select语句更改为
select count(id) ....
在MySQL 5.6中,ICP功能在这种情况下可能有所帮助,因为访问的所有字段都是索引的一部分。我相信当你指定count(*)时MySQL可能会读取实际的数据记录,因此它需要读取索引文件和数据文件。
答案 1 :(得分:0)
试试这个,有known MySQL issue日期时间索引
WHERE
created_at BETWEEN
CAST('2011-10-31 20:00:00' AS datetime) AND
CAST('2011-12-31 19:59:59' AS datetime)
答案 2 :(得分:0)