2017-02-18 76 views
1

所以我梳理了網絡,似乎無法找到答案。我有以下結構簡單選擇組通過使用filesort&tempory,而不是索引

Table structure for table `search_tags` 
-- 

CREATE TABLE IF NOT EXISTS `search_tags` (
    `ID` int(11) NOT NULL AUTO_INCREMENT, 
    `LOOK_UP_TO_CAT_ID` int(11) NOT NULL, 
    `SEARCH_TAG` text COLLATE utf8_unicode_520_ci NOT NULL, 
    `DATE` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, 
    `SOURCE` varchar(225) COLLATE utf8_unicode_520_ci NOT NULL, 
    `SOURCE_ID` int(11) NOT NULL, 
    `WEIGHT` int(11) NOT NULL DEFAULT '1000', 
    PRIMARY KEY (`ID`), 
    KEY `LOOK_UP_TO_CAT_ID` (`LOOK_UP_TO_CAT_ID`), 
    KEY `WEIGHT` (`WEIGHT`), 
    FULLTEXT KEY `SEARCH_TAG` (`SEARCH_TAG`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_520_ci AUTO_INCREMENT=1 ; 

表與坐行800000+和不斷增長的表。

當我使用LOOK_UP_TO_CAT_ID上的組運行查詢時,查詢運行需要1-2秒。我需要運行這個基地加入到其他表的多個版本,但是這似乎是其中的瓶頸在於如添加加入到這並不慢下來

SELECT LOOK_UP_TO_CAT_ID, WEIGHT 
FROM `search_tags` 
WHERE `SEARCH_TAG` LIKE '%metallica%' 
GROUP BY `LOOK_UP_TO_CAT_ID` 

卸下GROUP BY下降查詢時間縮短到0.1這似乎更加可以接受,但後來我重複了重複。

使用同組的節目,它的創建臨時表,而不是使用索引

+----+-------------+-------------+------+-------------------+------+---------+------+--------+----------------------------------------------+--+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows |     Extra      | | 
+----+-------------+-------------+------+-------------------+------+---------+------+--------+----------------------------------------------+--+ 
| 1 | SIMPLE  | search_tags | ALL | LOOK_UP_TO_CAT_ID | NULL | NULL | NULL | 825087 | Using where; Using temporary; Using filesort | | 
+----+-------------+-------------+------+-------------------+------+---------+------+--------+----------------------------------------------+--+ 

所以我不知道如果MySQL這裏還是沒有做正確的事情解釋一下,但對我來說,在至少它不錯,不使用索引。爲什麼要加快查詢的速度最好?

編輯:

我的繼承人數據的例子:

+----+-------------------+----------------------------------+------------+---------------+-----------+--------+ 
| ID | LOOK_UP_TO_CAT_ID |   SEARCH_TAG   | DATE | SOURCE  | SOURCE_ID | WEIGHT | 
+----+-------------------+----------------------------------+------------+---------------+-----------+--------+ 
| 1 |    521 | METALLICA      | 2017-02-18 | artist  |  15 |  1 | 
| 2 |    521 | METALLICA - NOTHING ELSE MATTERS | 2017-02-18 | tracklisting |  22 |  2 | 
| 3 |    522 | METALLICA      | 2017-02-18 | artist  |  15 |  1 | 
| 4 |    522 | METALLICA - ST. Anger   | 2017-02-18 | product_title |  522 |  2 | 
+----+-------------------+----------------------------------+------------+---------------+-----------+--------+ 

所需的結果

+-------------------+--------+ 
| LOOK_UP_TO_CAT_ID | WEIGHT | 
+-------------------+--------+ 
|    521 |  1 | 
|    522 |  1 | 
+-------------------+--------+ 
+1

將'SELECT *'與'GROUP BY'一起使用僅僅表示對SQL的理解不足。編輯您的問題並提供樣本數據和期望的結果。 –

回答

0

對你有幾點建議。

  1. SEARCH_TAG LIKE '%metallica%'在這個悲哀的世界裏,永遠不會使用索引。 haystack like '%needle'(導致%)模式要求MySQL檢查列中的每個值以進行匹配。 haystack LIKE 'needle%'(落後%)沒有這個問題。

  2. 您有a FULLTEXT index在您的SEARCH_TAG列,請使用它! WHERE MATCH('metallica') AGAINST SEARCH_TAG是您需要的WHERE子句的形式。

  3. 您的表格中有許多單列索引。除非這些查詢完全匹配您正在嘗試執行的操作,否則這些通常無助於加快查詢速度。使用爲您正在運行的查詢設計的compound covering indexes會更好。

在你的問題的例子查詢

SELECT LOOK_UP_TO_CAT_ID, WEIGHT 
    FROM search_tags 
    WHERE SEARCH_TAG LIKE '%metallica%' 
GROUP BY LOOK_UP_TO_CAT_ID 

如果改成這樣就會使更多的SQL感,運行速度更快。

SELECT LOOK_UP_TO_CAT_ID, MAX(WEIGHT) 
    FROM search_tags 
    WHERE SEARCH_TAG LIKE 'metallica%' 
GROUP BY LOOK_UP_TO_CAT_ID 

(請注意,我擺脫了領先%的。)

如果添加覆蓋指數的化合物上(SEARCH_TAG, LOOK_UP_CAT_ID, WEIGHT)此查詢會變得相當快。整個查詢可以通過索引來滿足。 MySQL隨機訪問索引以找到您的SEARCH_TAG,然後執行loose index scan以獲取您請求的結果。

(旁白:當你在一個GROUP BYORDER BY查詢EXPLAIN輸出看到filesortfilesort不要擔心這是MySQL的滿足查詢方式的一部分的文件並不一定意味着一個緩慢的文件)

+0

謝謝你的解釋。我已經與方法匹配,因爲這對我的情況非常有效(性能明智)。 – Mark

0

在某種程度上,你的問題就沒有意義了。您有一個全文索引,但使用LIKE,它進行表掃描。您需要使用MATCH()才能使用全文索引。

我真的認爲正在發生的事情是返回的數據量很大。當您在沒有order bygroup by的情況下執行查詢時,結果將在生成時返回。您會看到結果,因爲一些早期掃描的行符合您的條件。

A group by/order by需要讀取所有結果。

你可以做一個count(*),而不是select檢查:

SELECT COUNT(*) 
FROM `search_tags` 
WHERE `SEARCH_TAG` LIKE '%metallica%'; 

我懷疑這可能需要更長的時間。

您可以通過使用相關子查詢消除重複消除對性能的影響:

SELECT st.LOOK_UP_TO_CAT_ID, st.WEIGHT 
FROM `search_tags` st 
WHERE `SEARCH_TAG` LIKE '%metallica%' AND 
     st.id = (SELECT MIN(st2.id) FROM search_tags st2 WHERE st2.LOOK_UP_TO_CAT_ID = st.LOOK_UP_TO_CAT_ID); 

這尤其需要在search_tags(LOOK_UP_TO_CAT_ID, ID)的指數表現。

但是,您可能想要使用MATCH()以充分利用全文索引。

相關問題