2015-11-08 115 views
0

索引的大小對於我的網店我有一個表,我使用了搜索:MySQL的減少鉅額表

CREATE TABLE `store_search` (
    `term` varchar(50) NOT NULL DEFAULT '', 
    `content_id` int(10) unsigned NOT NULL, 
    `type` enum('keyword','tag') NOT NULL DEFAULT 'keyword', 
    `random` int(10) unsigned NOT NULL, 
    `saving` int(10) unsigned NOT NULL, 
    PRIMARY KEY (`content_id`,`term`,`type`), 
    UNIQUE KEY `saving` (`term`,`saving`,`random`,`content_id`,`type`), 
    UNIQUE KEY `random` (`term`,`random`,`content_id`,`type`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED 

產品可以以兩種方式列出:按隨機順序(基於欄random)或折扣(基於列saving)。過去的測試顯示,使用UNIQUE訂單的約束比使用標準索引與ORDER BY更有效。查詢可以是這樣的:

mysql> EXPLAIN SELECT content_id FROM store_search USE INDEX (random) WHERE term LIKE 'shirt%' AND type='keyword' LIMIT 2000,100; 
+----+-------------+--------------+-------+---------------+--------+---------+------+---------+--------------------------+ 
| id | select_type | table  | type | possible_keys | key | key_len | ref | rows | Extra     | 
+----+-------------+--------------+-------+---------------+--------+---------+------+---------+--------------------------+ 
| 1 | SIMPLE  | store_search | range | random  | random | 152  | NULL | 9870580 | Using where; Using index | 
+----+-------------+--------------+-------+---------------+--------+---------+------+---------+--------------------------+ 

這樣我就可以防止ORDER BY條款(沒有文件排序中,這種方法做)。

mysql> EXPLAIN SELECT DISTINCT x.content_id 
    -> FROM store_search x USE INDEX (saving) 
    -> INNER JOIN store_search y ON x.content_id=y.content_id 
    -> WHERE x.term LIKE 'shirt%' AND x.type='keyword' AND y.term LIKE 'blue%' AND y.type='keyword' 
    -> LIMIT 0,100; 
+----+-------------+-------+-------+-----------------------+---------+---------+--------------+----------+-------------------------------------------+ 
| id | select_type | table | type | possible_keys   | key  | key_len | ref   | rows  | Extra          | 
+----+-------------+-------+-------+-----------------------+---------+---------+--------------+----------+-------------------------------------------+ 
| 1 | SIMPLE  | x  | range | PRIMARY,saving,random | saving | 152  | NULL   | 11449970 | Using where; Using index; Using temporary | 
| 1 | SIMPLE  | y  | ref | PRIMARY,saving,random | PRIMARY | 4  | x.content_id |  20 | Using where; Using index; Distinct  | 
+----+-------------+-------+-------+-----------------------+---------+---------+--------------+----------+-------------------------------------------+ 

正如我所說的,這個解決方案是好的迄今:PRIMARY KEY用於自搜索多個術語時加入。我現在的問題是:目前這張表(〜500mio行)非常龐大,索引不再適合內存。這導致,INSERTUPDATE語句非常慢。數據需要23GB和索引消耗32GB,所以這張表的55GB。測試是可能的,但複製這張表時會消耗大量時間,但是有沒有人可以減少索引大小? 我想將字符串列的排序轉換爲latin_1,但我可以合併一些索引嗎?

+0

列** **中的不同值的數量限制爲幾個或者它們是否是真正的自由文本? – trincot

+0

這些確實是免費的文字。長期限制爲50個字符。 – rabudde

+0

您實際需要向最終用戶提供的記錄數是否有限制?我的意思是,如果你得到10000場比賽,你是否真的需要全部提供? – trincot

回答

1

term LIKE 'shirt%'範圍查找INDEX(term, ...)將不會通過term進行過濾,以便到達type或其他列。

這和其他基本索引原則在我的Index Cookbook中討論。

因此... WHERE term LIKE 'shirt%' AND type='keyword'請求INDEX(keyword, term)。並且在過濾中添加任何其他列將無濟於事。

但是,您所依賴的是涵蓋。這是所有需要的列在單個索引中的位置。在這種情況下,可以在索引BTree中執行查詢而不觸及數據BTree。也就是說,增加額外的列可以是有益的。

多事情

SELECT content_id 
    FROM store_search USE INDEX (random) 
    WHERE term LIKE 'shirt%' 
     AND type='keyword' 
    LIMIT 2000,100; 
UNIQUE KEY `random` (`term`,`random`,`content_id`,`type`) 

怎麼回事是一些:

  • 該指數是 「覆蓋」。
  • 沒有ORDER BY,所以輸出可能首先按term排序(假設可能有多個以'shirt'開頭的短語),並且僅次於random。這不是你想要的,但可能會發生作用。
  • LIMIT要求掃描2000 + 100行索引,然後退出。如果襯衫不夠,它會停下來。這可能看起來「很快」。
  • UNIQUE可能是不相關的,並且對於插入是浪費的。

下一個查詢讓我們來剖析SELECT DISTINCT x.content_id ...

  • 您用DISTINCT的類似(可能更快)的代碼替換了「filesort」。可能沒有淨收益;時間吧。
  • 如果有999件藍色襯衫,它會找到全部999件,然後將它們分開,然後交付100件。
  • 如果沒有ORDER BY,則無法預測將交付哪100個。
  • 由於您已經收集了所有999,因此添加ORDER BY RAND()不會增加太多開銷。
  • 你真的想讓'藍綠'襯衫迴歸,但不是'淺藍'嗎? 「衣服%」拿起「褲子褲子」呢?淫。

底線

  • PRIMARY KEY(type, term, content_id)更換3個索引。通過PK進入,你有效地「覆蓋」。
  • 使用ORDER BY randomORDER BY RAND() - 請參閱哪個更適合您。 (後者是更隨意!)
  • LIKE 'shirt%'

重新思考外卡底部的底線是,EAV架構設計很爛。我討論這個further

+0

要更新這個問題:正如我所提到的,查詢時間並不是那麼糟糕。我嘗試了不同索引的很多方法。緩慢的事情是更新表。所以我們決定使用Solr來檢索必須在流中顯示的內容ID,現在很好,因爲巨大的search_ *表已經消失了。 – rabudde

+0

'innodb_buffer_pool_size'應該設置爲_available_ RAM的大約70%。 –