即使在大表上使用索引也会查询速度慢

时间:2016-11-27 09:56:01

标签: mysql

我正在执行一个简单的选择查询来从表日志中提取用户名(包含54864行)。 检索数据花了大约7.836秒。 我怎样才能加快效果?

SELECT username FROM `logs`
WHERE 
logs.branch=1 
and
logs.added_on > '2016-11-27 00:00:00'

在描述表格时,

+-------------------+-------------+------+-----+---------+----------------+
| Field             | Type        | Null | Key | Default | Extra          |
+-------------------+-------------+------+-----+---------+----------------+
| id                | int(11)     | NO   | PRI | NULL    | auto_increment |
| username          | char(255)   | YES  | MUL | NULL    |                |
| fullname          | char(255)   | YES  |     | NULL    |                |
| package           | char(255)   | YES  |     | NULL    |                |
| prev_expiry       | date        | YES  |     | NULL    |                |
| recharged_upto    | date        | YES  |     | NULL    |                |
| payment_option    | int(11)     | YES  | MUL | NULL    |                |
| amount            | float(14,2) | YES  |     | NULL    |                |
| branch            | int(11)     | YES  | MUL | NULL    |                |
| added_by          | int(11)     | YES  |     | NULL    |                |
| added_on          | datetime    | YES  | MUL | NULL    |                |
| remark            | text        | YES  |     | NULL    |                |
| payment_mode      | char(255)   | YES  |     | NULL    |                |
| recharge_duration | char(255)   | YES  |     | NULL    |                |
| invoice_number    | char(255)   | YES  |     | NULL    |                |
| cheque_no         | char(255)   | YES  |     | NULL    |                |
| bank_name         | char(255)   | YES  |     | NULL    |                |
| verify_by_ac      | int(11)     | YES  |     | 0       |                |
| adjusted_days     | int(11)     | YES  |     | NULL    |                |
| adjustment_note   | text        | YES  |     | NULL    |                |
+-------------------+-------------+------+-----+---------+----------------+
20 rows in set

解释查询,

+----+-------------+--------------------------+------+-----------------------------+--------------+---------+-------+------+-------------+
| id | select_type | table                    | type | possible_keys               | key          | key_len | ref   | rows | Extra       |
+----+-------------+--------------------------+------+-----------------------------+--------------+---------+-------+------+-------------+
|  1 | SIMPLE      | logs                     | ref  | branch_index,added_on_index | branch_index | 5       | const |   37 | Using where |
+----+-------------+--------------------------+------+-----------------------------+--------------+---------+-------+------+-------------+
1 row in set

更新::在添加复合索引(branch_added_index)后解释查询

+----+-------------+--------------------------+------+------------------------------------------------+--------------+---------+-------+------+-------------+
| id | select_type | table                    | type | possible_keys                                  | key          | key_len | ref   | rows | Extra       |
+----+-------------+--------------------------+------+------------------------------------------------+--------------+---------+-------+------+-------------+
|  1 | SIMPLE      | logs                     | ref  | branch_index,added_on_index,branch_added_index | branch_index | 5       | const |   37 | Using where |
+----+-------------+--------------------------+------+------------------------------------------------+--------------+---------+-------+------+-------------+
1 row in set

4 个答案:

答案 0 :(得分:2)

branch,added_on上添加一个复合键,因此您可以覆盖所有WHERE条件,因为您使用了AND。

ALTER TABLE logs ADD KEY(branch,added_on)

这应该快得多,你也可以删除branch_index键,因为上面的索引可以替换它。你只能从54000返回37行,所以基数没问题。

ALTER TABLE logs DROP INDEX `branch_index`;

或者您可以使用索引提示

SELECT username FROM `logs` USE INDEX (branch_added_index)  WHERE 
logs.branch=1 
and
logs.added_on > '2016-11-27 00:00:00'

答案 1 :(得分:2)

如果您的表的现有索引已用于其他查询,请尝试添加如下所示的新复合索引 create index <indexname> on logs(branch,added_on)

答案 2 :(得分:1)

在2个字段(branch,added_on)上创建一个复合索引,如:

ALTER TABLE `logs` ADD KEY idx_branch_added (branch, added_on);

答案 3 :(得分:1)

这会更快,因为它是“覆盖”:

INDEX(branch, added_on, username) -- in exactly that order.

(并删除任何作为前缀的索引。)

Index Cookbook

“基数”很少有重要性。并且EXPLAIN经常会出现错误的价值。

EXPLAIN显示5 branch的大小 - 是否真的需要NULLable?你会有20亿支?考虑使用更小的东西,例如1字节TINYINT UNSIGNED NOT NULL(值0..255)。

另外,将255缩小到合理的范围。

在描述表格时,请使用SHOW CREATE TABLE;它更具描述性。了解引擎,Charset等可能会有所帮助。