2

我有以下简单的 MySQL 查询:

SELECT SQL_NO_CACHE mainID
FROM tableName 
WHERE otherID3=19
AND dateStartCol >= '2012-08-01' 
AND dateStartCol <= '2012-08-31';

当我运行它时,需要 0.29 秒才能带回 36074 个结果。当我增加我的日期周期以带回更多结果(65703)时,它运行在 0.56。当我在同一台服务器上但在不同的表(有些表更大)上运行其他类似的 SQL 查询时,结果会在大约 0.01 秒内返回。

虽然 0.29 并不慢 - 这是复杂查询的基本部分,而且这个时间意味着它不可扩展。

有关表定义和索引,请参见下文。

我知道这不是服务器负载,因为我在使用很少的开发服务器上遇到了同样的问题。

+---------------------------+--------------+------+-----+---------+----------------+
| Field                     | Type         | Null | Key | Default | Extra          |
+---------------------------+--------------+------+-----+---------+----------------+
| mainID                    | int(11)      | NO   | PRI | NULL    | auto_increment |
| otherID1                  | int(11)      | NO   | MUL | NULL    |                |
| otherID2                  | int(11)      | NO   | MUL | NULL    |                |
| otherID3                  | int(11)      | NO   | MUL | NULL    |                |
| keyword                   | varchar(200) | NO   | MUL | NULL    |                |
| dateStartCol              | date         | NO   | MUL | NULL    |                |
| timeStartCol              | time         | NO   | MUL | NULL    |                |
| dateEndCol                | date         | NO   | MUL | NULL    |                |
| timeEndCol                | time         | NO   | MUL | NULL    |                |
| statusCode                | int(1)       | NO   | MUL | NULL    |                |
| uRL                       | text         | NO   |     | NULL    |                |
| hostname                  | varchar(200) | YES  | MUL | NULL    |                |
| IPAddress                 | varchar(25)  | YES  |     | NULL    |                |
| cookieVal                 | varchar(100) | NO   |     | NULL    |                |
| keywordVal                | varchar(60)  | NO   |     | NULL    |                |
| dateTimeCol               | datetime     | NO   | MUL | NULL    |                |
+---------------------------+--------------+------+-----+---------+----------------+


+--------------------+------------+-------------------------------+--------------+---------------------------+-----------+-------------+----------+--------+------+------------+---------+
| Table              | Non_unique | Key_name                      | Seq_in_index | Column_name               | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+--------------------+------------+-------------------------------+--------------+---------------------------+-----------+-------------+----------+--------+------+------------+---------+
| tableName          |          0 | PRIMARY                       |            1 | mainID                    | A         |      661990 |     NULL | NULL   |      | BTREE      |         |
| tableName          |          1 | idx_otherID1                  |            1 | otherID1                   | A         |      330995 |     NULL | NULL   |      | BTREE      |         |
| tableName          |          1 | idx_otherID2                  |            1 | otherID2                   | A         |          25 |     NULL | NULL   |      | BTREE      |         |
| tableName          |          1 | idx_otherID3                  |            1 | otherID3                   | A         |          48 |     NULL | NULL   |      | BTREE      |         |
| tableName          |          1 | idx_dateStartCol              |            1 | dateStartCol               | A         |         187 |     NULL | NULL   |      | BTREE      |         |
| tableName          |          1 | idx_timeStartCol              |            1 | timeStartCol               | A         |       73554 |     NULL | NULL   |      | BTREE      |         |
|tableName          |          1 | idx_dateEndCol                 |            1 | dateEndCol                 | A         |         188 |     NULL | NULL   |      | BTREE      |         |
|tableName          |          1 | idx_timeEndCol                 |            1 | timeEndCol                 | A         |       73554 |     NULL | NULL   |      | BTREE      |         |
| tableName          |          1 | idx_keyword                   |            1 | keyword                    | A         |       82748 |     NULL | NULL   |      | BTREE      |         |
| tableName           |          1 | idx_hostname                 |            1 | hostname                   | A         |        2955 |     NULL | NULL   | YES  | BTREE      |         |
| tableName           |          1 | idx_dateTimeCol              |            1 | dateTimeCol                | A         |      220663 |     NULL | NULL   |      | BTREE      |         |
| tableName           |          1 | idx_statusCode               |            1 | statusCode                 | A         |           2 |     NULL | NULL   |      | BTREE      |         |
+--------------------+------------+-------------------------------+--------------+---------------------------+-----------+-------------+----------+--------+------+------------+---------+

解释输出:

+----+-------------+-----------+-------+----------------------------------+-------------------+---------+------+-------+----------+-------------+
| id | select_type | table     | type  | possible_keys                    | key               | key_len | ref  | rows  | filtered | Extra       |
+----+-------------+-----------+-------+----------------------------------+-------------------+---------+------+-------+----------+-------------+
|  1 | SIMPLE      | tableName | range | idx_otherID3,idx_dateStartCol | idx_dateStartCol | 3       | NULL | 66875 |    75.00 | Using where |
+----+-------------+-----------+-------+----------------------------------+-------------------+---------+------+-------+----------+-------------+
4

3 回答 3

1

如果这确实是您的查询(而不是相同的简化版本),那么这应该可以达到最佳结果:

 CREATE INDEX table_ndx on tableName( otherID3, dateStartCol, mainID);

第一个索引条目意味着第一个匹配WHERE非常快;这同样适用于dateStartCol。第三个字段非常小,不会显着降低索引速度,但允许在索引中立即找到您需要的数据,而根本不需要表访问。

重要的是键在同一个索引中。在EXPLAIN您发布的帖子中,每个键都在自己的索引中,因此即使 MySQL 选择最佳索引,性能也不会最佳。我会尝试使用更少的索引,因为它们也有成本(无耻的插件:索引实际上会降低 SELECT 性能吗?)。

于 2012-10-16T11:07:39.993 回答
0

如果这是一个经常性或重要的查询,则创建一个多列索引:

CREATE INDEX index_name ON tableName (otherID3, dateStartCol)

删除未使用的索引,因为它们会使表更改更加昂贵。

顺便说一句,您不需要两个单独的日期和时间列。然后你可以在一个datetimetimestamp类型中组合。少一列和少一索引。

explain输出显示它选择了dateStartCol索引,因此您可以尝试我上面建议的相反方法:

CREATE INDEX index_name ON tableName (dateStartCol, otherID3)

请注意,查询的 dateStartCol 条件仍将获得 75% 的行,因此在使用该单个索引时没有太大改进(如果有的话)。

有多独特otherID3?如果重复的次数不多,otherID3您可以提示引擎使用它。

于 2012-10-16T10:51:48.450 回答
0

首先尝试添加正确的密钥。似乎 dateStartCol 比 otherID3 更具选择性

ALTER TABLE tableName ADD KEY idx_dates(dateStartCol, dateStartCol)

其次 - 请确保通过将 LIMIT 子句添加到 SELECT 来仅选择所需的行。这将提高查询。试试这样:

SELECT SQL_NO_CACHE mainID FROM tableName WHERE otherID3=19 AND dateStartCol >= '2012-08-01' AND dateStartCol <= '2012-08-31' LIMIT 10;

还请确保您的 MySQL 已正确调整。您可能需要检查 key_buffer_size 和 innodb_buffer_pool_size,如http://astellar.com/2011/12/why-is-stock-mysql-slow/中所述

于 2012-10-16T11:01:16.177 回答