2012-06-07 64 views
7
MySQL Server version: 5.0.95 
Tables All: InnoDB 

我有一個MySQL數據庫查詢的問題。基本上我發現,如果我索引一個特定的varchar(50)字段tag.name,我的查詢需要更長的時間(x10)而不是索引字段。我試圖加快這個查詢,但是我的努力似乎是反作用的。MySQL索引的放緩查詢

罪魁禍首行和場似乎是:

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

我注意到,如果我直接查詢tag表沒有使用相同的標準加入,與索引的名稱字段中,我沒有問題..它實際上按預期運作得更快。

示例查詢**

 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 **

| 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而不指數**

+----+-------------+-------+--------+--------------------------+---------+---------+---------------------+------+-------------+ 
| 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 | 
+----+-------------+-------+--------+--------------------------+---------+---------+---------------------+------+-------------+ 

表中創建

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 

指數法

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  |   | 
+---------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 

最終解決 看來,MySQL的只是排序的數據不正確。最後,它更快地將標記表看作是返回標識的子查詢。

+2

其他表上的索引是什麼?每個指數報告的基數是多少?你最近分析過他們嗎? – symcbean

+0

贊同sym,試着喲分析它看起來像filesort搞砸了 – jcho360

+0

請看看這個頁面:http://www.mysqlperformanceblog.com/2009/03/05/what-does-using-filesort-mean -in-mysql/ – jcho360

回答

1

有多大你的表? 我注意到在第一次解釋你有一個「使用臨時;使用filesort」這是不好的。您的查詢可能被轉儲到光盤,這使得它比內存查詢更慢。 也儘量避免使用「select *」,而是查詢所需的最小字段。

+0

它是我的例子,但謝謝你的提示。我知道使用文件排序是一個問題,但我不明白爲什麼會發生。當我添加索引使用filesort ..刪除索引,它工作正常.. – Lee

+0

我剛剛跑到這個線程:http://forums.mysql.com/read.php?115,73760,73760#msg- 73760他們的建議是爲你的tag.name製作一個查找表,這樣你就可以在數據表中使用與名稱本身分開的整數 –

+0

這就是我解決問題的方法。通過在標籤表上執行單個查找更快名稱作爲子查詢。 :D ..感謝您的信息。 – Lee

3

似乎article_id的是文章表的主鍵。

既然你通過article_id的分組,MySQL需要通過該列,以返回記錄,以執行GROUP BY。

你可以看到,如果沒有索引,則掃描物品表中的所有記錄,但他們至少爲了通過article_id的,所以最遲排序是必需的。 LIMIT優化可以在這裏應用,因爲它已經是有序的,它可以在五行之後停止。

而不是掃描整個表的文章

在與tag.name索引查詢,它採用了指數,但對標籤表,並從那裏開始。不幸的是,這樣做時,記錄必須稍後按article.article_id排序才能完成GROUP BY子句。 LIMIT優化無法應用,因爲它必須返回整個結果集,然後對其進行排序,以獲得前5行。

在這種情況下,MySQL只是猜測錯誤。

沒有LIMIT子句,我猜測使用索引更快,這也許是MySQL猜測的。