2016-12-30 104 views
1

我有这个疑问:查询中未使用索引。如何提高性能?

SELECT 
    * 
FROM 
    `av_cita` 
JOIN `av_cita_cstm` ON (
    (
     `av_cita`.`id` = `av_cita_cstm`.`id_c` 
    ) 
) 
WHERE 
    av_cita.deleted = 0 

此查询时间超过120秒完成,但我已经添加的所有索引。

当我问执行计划:

explain SELECT * FROM `av_cita` 
     JOIN `av_cita_cstm` ON ((`av_cita`.`id` = `av_cita_cstm`.`id_c`)) 
     WHERE av_cita.deleted = 0; 

我得到这个:

+----+-------------+--------------+--------+----------------------+---------+---------+---------------------------+--------+-------------+ 
| id | select_type | table  | type | possible_keys  | key  | key_len | ref      | rows | Extra  | 
+----+-------------+--------------+--------+----------------------+---------+---------+---------------------------+--------+-------------+ 
| 1 | SIMPLE  | av_cita  | ALL | PRIMARY,delete_index | NULL | NULL | NULL      | 192549 | Using where | 
| 1 | SIMPLE  | av_cita_cstm | eq_ref | PRIMARY    | PRIMARY | 108  | rednacional_v2.av_cita.id |  1 |    | 
+----+-------------+--------------+--------+----------------------+---------+---------+---------------------------+--------+-------------+ 

delete_indexpossible_keys列中列出,但关键是null,并且它不使用该指数。

表和索引定义:

+------------------+--------------+------+-----+---------+-------+ 
| Field   | Type   | Null | Key | Default | Extra | 
+------------------+--------------+------+-----+---------+-------+ 
| id    | char(36)  | NO | PRI | NULL |  | 
| name    | varchar(255) | YES | MUL | NULL |  | 
| date_entered  | datetime  | YES | MUL | NULL |  | 
| date_modified | datetime  | YES |  | NULL |  | 
| modified_user_id | char(36)  | YES |  | NULL |  | 
| created_by  | char(36)  | YES | MUL | NULL |  | 
| description  | text   | YES |  | NULL |  | 
| deleted   | tinyint(1) | YES | MUL | 0  |  | 
| assigned_user_id | char(36)  | YES | MUL | NULL |  | 
+------------------+--------------+------+-----+---------+-------+ 
+---------+------------+--------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| Table | Non_unique | Key_name   | Seq_in_index | Column_name  | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | 
+---------+------------+--------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| av_cita |   0 | PRIMARY   |   1 | id    | A   |  192786 |  NULL | NULL |  | BTREE  |   |    | 
| av_cita |   1 | delete_index  |   1 | deleted   | A   |   2 |  NULL | NULL | YES | BTREE  |   |    | 
| av_cita |   1 | name_index   |   1 | name    | A   |  96393 |  NULL | NULL | YES | BTREE  |   |    | 
| av_cita |   1 | date_entered_index |   1 | date_entered  | A   |  96393 |  NULL | NULL | YES | BTREE  |   |    | 
| av_cita |   1 | created_by   |   1 | created_by  | A   |   123 |  NULL | NULL | YES | BTREE  |   |    | 
| av_cita |   1 | assigned_user_id |   1 | assigned_user_id | A   |  1276 |  NULL | NULL | YES | BTREE  |   |    | 
| av_cita |   1 | deleted_id   |   1 | deleted   | A   |   2 |  NULL | NULL | YES | BTREE  |   |    | 
| av_cita |   1 | deleted_id   |   2 | id    | A   |  192786 |  NULL | NULL |  | BTREE  |   |    | 
| av_cita |   1 | id     |   1 | id    | A   |  192786 |  NULL | NULL |  | BTREE  |   |    | 
+---------+------------+--------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 

我怎样才能提高此查询的性能?

+0

您可能想要显示“av_cita”的表格和所有索引定义。 – mustaccio

+0

对不起,男人,[url = http://i.imgur.com/F4KPAnm.png] [img] http://imgur.com/F4KPAnml.png [/ img] [/ url] –

+0

http:// imgur.com/F4KPAnml.png http://imgur.com/irgBnldl.png –

回答

0

该查询正在失去进行连接的时间。我强烈建议在av_cita_cstm.id_c上创建和索引。那么该计划可能会更改为使用av_cita_cstm表的索引,这比PRIMARY要好得多。因此PRIMARY将在ac_cita上使用。

我认为这会带来很大的改善。如果确保delete_index使用两个字段进行定义:(deleted, id),然后将SQL语句的where条件移动到join条件中,您可能仍会获得更多改进。但我不确定MySql会认为这是可能的。

+0

谢谢你的快速回答。我会尝试 !! –

+0

我做到了,并采取相同的结果。无论如何 –

+0

你能否像你对'av_cita'所做的那样向你的问题添加'av_cita_cstm'上现有索引的信息? – trincot

0

deleted上的索引不被使用可能是因为优化器已经决定全表扫描比使用索引便宜。如果在表中大约20%或更多的行上找到您搜索的值,MySQL往往会做出这个决定。

以类推的方式,想一想书后面的索引。你可以理解为什么像“”这样的常见词汇没有编入索引。只读封面封面比翻转索引要容易得多,索引只会告诉你“”出现在大多数页面上。

如果你认为MySQL已经做出了错误的决定,你可以把它假装表扫描比使用一个特定的指数更加昂贵:

SELECT 
    * 
FROM 
    `av_cita` FORCE INDEX (deleted_index) 
JOIN `av_cita_cstm` ON (
    (
     `av_cita`.`id` = `av_cita_cstm`.`id_c` 
    ) 
) 
WHERE 
    av_cita.deleted = 0 

阅读http://dev.mysql.com/doc/refman/5.7/en/index-hints.html有关索引提示的更多信息。不要过度使用索引提示,它们仅在极少数情况下才有用。大多数情况下,优化器做出正确的决定。

您的EXPLAIN计划显示,您加入av_cita_cstm已经在使用唯一索引(线索为“type:eq_ref”,也是“rows:1”)。我认为该表中不需要任何新索引。

我注意到EXPLAIN显示av_cita上的表扫描大概估计192549行。我真的很惊讶,这需要120秒。在任何功能相当强大的计算机上,运行速度要快得多。

这使我不知道,如果你有别的东西,需要在此服务器上的调整或配置:

  • 哪些进程正在服务器上运行?很多应用程序,也许?其他进程是否也在此服务器上运行缓慢?你需要增加服务器的功能,还是将应用程序移动到他们自己的服务器上?

    如果你在MySQL 5.7,尝试查询sys架构:本:

    select * from sys.innodb_buffer_stats_by_table 
    where object_name like 'av_cita%'; 
    
  • 同时运行有其他昂贵的SQL查询?

  • 您是否分配了MySQL的innodb_buffer_pool_size?如果它太小,它可能会疯狂地回收RAM中的页面,因为它会扫描您的表格。

    select @@innodb_buffer_pool_size; 
    
  • 您是否超额分配innodb_buffer_pool_size?一旦我帮助调整运行速度非常缓慢的服务器。原来他们有一个4GB的缓冲池,但只有1GB的物理RAM。操作系统疯狂交换,导致一切运行缓慢。

另一个想法:你们充分展示了该列av_cita,但不表结构av_cita_cstm。你为什么取SELECT *?你真的需要所有的列吗?后面的表中是否有巨大的BLOB/TEXT列?如果是这样,它可能会从磁盘读取大量不需要的数据。

当你问SQL的问题,如果你运行

SHOW CREATE TABLE av_cita\G 
SHOW TABLE STATUS LIKE 'av_cita'\G 

而且还运行其它表av_cita_cstm相同的命令,并且包括在上面你的问题的输出,这将有助于。