简单的MySQL查询与性能问题

时间:2012-10-16 10:41:06

标签: mysql performance

我有以下简单的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 |
+----+-------------+-----------+-------+----------------------------------+-------------------+---------+------+-------+----------+-------------+

3 个答案:

答案 0 :(得分:1)

如果这确实是你的查询(而不是它的简化版本),那么这应该是最好的结果:

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

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

密钥必须位于相同的索引中。在您发布的EXPLAIN中,每个键都在其自己的索引中,因此即使MySQL选择最佳索引,性能也不会是最佳的。我尝试使用较少的索引,因为它们也有成本(无耻的插件:Can Indices actually decrease SELECT performance?)。

答案 1 :(得分:0)

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

CREATE INDEX index_name ON tableName (otherID3, dateStartCol)

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

顺便说一下,您不需要两个单独的列来表示日期和时间。您可以在datetimetimestamp类型中合并。少一列,少一个索引。

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

CREATE INDEX index_name ON tableName (dateStartCol, otherID3)

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

otherID3有多独特?如果没有多少重复otherID3,您可以hint引擎使用它。

答案 2 :(得分:0)

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

ALTER TABLE tableName ADD KEY idx_dates(dateStartCol, dateStartCol)

第二 - 请确保通过向SELECT添加LIMIT子句来仅选择所需的行。这应该是查询。试试这样:

SELECT SQL_NO_CACHE mainID FROM tableName 其他ID = 19 AND dateStartCol&gt; =''2012-08-01' AND dateStartCol&lt; =''2012-08-31' 限制10;

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

中所述