简体   繁体   English

MySQL索引减慢了查询速度

[英]MySQL index slowing down query

MySQL Server version: 5.0.95
Tables All: InnoDB

I am having an issue with a MySQL db query. 我遇到了MySQL数据库查询的问题。 Basically I am finding that if I index a particular varchar(50) field tag.name , my queries take longer (x10) than not indexing the field. 基本上我发现如果我索引一个特定的varchar(50)字段tag.name ,我的查询需要更长的时间(x10)而不是索引字段。 I am trying to speed this query up, however my efforts seem to be counter productive. 我正试图加快这个问题,但是我的努力似乎反效果。

The culprit line and field seems to be: 罪魁祸首线和领域似乎是:

WHERE `t`.`name` IN ('news','home')

I have noticed that if i query the tag table directly without a join using the same criteria and with the name field indexed, i do not have the issue.. It actually works faster as expected. 我注意到,如果我直接查询tag表而没有使用相同条件和名称字段索引的连接,我没有问题..它实际上工作得更快。

EXAMPLE Query ** 示例查询**

      SELECT `a`.*, `u`.`pen_name`
        FROM `tag_link` `tl`
  INNER JOIN `tag` `t`
          ON `t`.`tag_id` = `tl`.`tag_id`
  INNER JOIN `article` `a` 
          ON `a`.`article_id` = `tl`.`link_id`
  INNER JOIN `user` `u`
          ON `a`.`user_id` = `u`.`user_id`   
       WHERE `t`.`name` IN ('news','home')
         AND `tl`.`type` = 'article'
         AND `a`.`featured` = 'featured'
    GROUP BY `article_id`
       LIMIT 0 , 5

EXPLAIN with index ** 使用索引**进行说明

| id | select_type | table | type   | possible_keys            | key     | key_len | ref               | rows | Extra                                                     |
+----+-------------+-------+--------+--------------------------+---------+---------+-------------------+------+-----------------------------------------------------------+
|  1 | SIMPLE      | t     | range  | PRIMARY,name             | name    | 152     | NULL              |    4 | Using where; Using index; Using temporary; Using filesort | 
|  1 | SIMPLE      | tl    | ref    | tag_id,link_id,link_id_2 | tag_id  | 4       | portal.t.tag_id   |   10 | Using where                                               | 
|  1 | SIMPLE      | a     | eq_ref | PRIMARY,fk_article_user1 | PRIMARY | 4       | portal.tl.link_id |    1 | Using where                                               | 
|  1 | SIMPLE      | u     | eq_ref | PRIMARY                  | PRIMARY | 4       | portal.a.user_id  |    1 |                                                           | 
+----+-------------+-------+--------+--------------------------+---------+---------+-------------------+------+-----------------------------------------------------------+

EXPLAIN without index ** 没有索引的EXPLAIN **

+----+-------------+-------+--------+--------------------------+---------+---------+---------------------+------+-------------+
| id | select_type | table | type   | possible_keys            | key     | key_len | ref                 | rows | Extra       |
+----+-------------+-------+--------+--------------------------+---------+---------+---------------------+------+-------------+
|  1 | SIMPLE      | a     | index  | PRIMARY,fk_article_user1 | PRIMARY | 4       | NULL                | 8742 | Using where | 
|  1 | SIMPLE      | u     | eq_ref | PRIMARY                  | PRIMARY | 4       | portal.a.user_id    |    1 |             | 
|  1 | SIMPLE      | tl    | ref    | tag_id,link_id,link_id_2 | link_id | 4       | portal.a.article_id |    3 | Using where | 
|  1 | SIMPLE      | t     | eq_ref | PRIMARY                  | PRIMARY | 4       | portal.tl.tag_id    |    1 | Using where | 
+----+-------------+-------+--------+--------------------------+---------+---------+---------------------+------+-------------+

TABLE CREATE 表创建

CREATE TABLE `tag` (
  `tag_id` int(11) NOT NULL auto_increment,
  `name` varchar(50) NOT NULL,
  `type` enum('layout','image') NOT NULL,
  `create_dttm` datetime default NULL,
  PRIMARY KEY  (`tag_id`)
) ENGINE=InnoDB AUTO_INCREMENT=43077 DEFAULT CHARSET=utf8 

INDEXS 指数法

SHOW INDEX FROM tag_link;
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table    | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| tag_link |          0 | PRIMARY  |            1 | tag_link_id | A         |       42023 |     NULL | NULL   |      | BTREE      |         |
| tag_link |          1 | tag_id   |            1 | tag_id      | A         |       10505 |     NULL | NULL   |      | BTREE      |         |
| tag_link |          1 | link_id  |            1 | link_id     | A         |       14007 |     NULL | NULL   |      | BTREE      |         |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+

SHOW INDEX FROM article;
+---------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table   | Non_unique | Key_name         | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+---------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| article |          0 | PRIMARY          |            1 | article_id  | A         |        5723 |     NULL | NULL   |      | BTREE      |         |
| article |          1 | fk_article_user1 |            1 | user_id     | A         |           1 |     NULL | NULL   |      | BTREE      |         |
| article |          1 | create_dttm      |            1 | create_dttm | A         |        5723 |     NULL | NULL   | YES  | BTREE      |         |
+---------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+

Final Solution It seems that MySQL is just sorted the data incorrectly. 最终解决方案似乎MySQL只是错误地对数据进行了排序。 In the end it turned out faster to look at the tag table as a sub query returning the ids. 最后,将标签表看作返回id的子查询更快。

It seems that article_id is the primary key for the article table. 看来article_id是文章表的主键。

Since you're grouping by article_id, MySQL needs to return the records in order by that column, in order to perform the GROUP BY. 由于您按article_id进行分组,因此MySQL需要按该列按顺序返回记录,以便执行GROUP BY。

You can see that without the index, it scans all records in the article table, but they're at least in order by article_id, so no later sort is required. 您可以看到,如果没有索引,它会扫描文章表中的所有记录,但它们至少按照article_id顺序排列,因此不需要以后排序。 The LIMIT optimization can be applied here, since it's already in order, it can just stop after it gets five rows. LIMIT优化可以在这里应用,因为它已经按顺序排列,它可以在它获得五行后停止。

In the query with the index on tag.name, instead of scanning the entire articles table, it utilizes the index, but against the tag table, and starts there. 在带有tag.name索引的查询中,它不是扫描整个articles表,而是使用索引,但是对着tag表,从那里开始。 Unfortunately, when doing this, the records must later be sorted by article.article_id in order to complete the GROUP BY clause. 不幸的是,在执行此操作时,稍后必须按article.article_id对记录进行排序才能完成GROUP BY子句。 The LIMIT optimization can't be applied since it must return the entire result set, then order it, in order to get the first 5 rows. 无法应用LIMIT优化,因为它必须返回整个结果集,然后对其进行排序,以获得前5行。

In this case, MySQL just guesses wrongly. 在这种情况下,MySQL只是猜错了。

Without the LIMIT clause, I'm guessing that using the index is faster, which is maybe what MySQL was guessing. 没有LIMIT子句,我猜测使用索引更快,这可能是MySQL猜测的。

How big are your tables? 你的桌子有多大? I noticed in the first explain you have a "Using temporary; Using filesort" which is bad. 我注意到在第一个解释中你有一个“使用临时;使用filesort”这是不好的。 Your query is likely being dumped to disc which makes it way slower than in memory queries. 您的查询很可能被转储到光盘,这使得它比内存查询慢。 Also try to avoid using "select *" and instead query the minimum fields needed. 还要尽量避免使用“select *”,而是查询所需的最小字段。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM