2011-09-07 81 views
1

考慮這個查詢:SQL的性能和連接語句

SELECT DISTINCT (linkindex_tags.link_id) 
    , links_sorted.link_title 
    , links_sorted.link_url 
FROM linkindex_tags 
INNER JOIN links_sorted ON links_sorted.link_id = linkindex_tags.link_id 
ORDER BY 
(
IF (word_id = 400, 1,0)+ 
IF (word_id = 177, 1,0)+ 
IF (word_id = 114, 1,0)+ 
IF (word_id = 9, 1,0)+ 
IF (word_id = 270, 1,0)+ 
IF (word_id = 715, 1,0)+ 
IF (word_id = 279, 1,0)+ 
IF (word_id = 1, 1,0)+ 
IF (word_id = 1748, 1,0) 
) DESC 
LIMIT 0,15; 

因此,通過這些比賽的比分尋找匹配的一系列word_id的和odering(如找到5個word_ids一個鏈接,然後這是5分)

的linkindex_tags表目前是552196行(33 MB),但EXPAN到數百萬 的link_sorted表目前是823600(558MB - 每行OBV更多的數據)行,但也將擴大到更多。 linkindex_tags表可能會比links_sorted大8-12倍。

執行時間:本地i3核心Windows 7機器上7.069秒。 我的服務器是CentOs 64位8GB內存英特爾至強3470(四核) - 所以這將有助於在這個問題上我猜想可以分配出色的內存分配。

它運行緩慢,想知道我的方法是否全部錯誤。下面是從輪廓擊穿慢位:

複製到tmp下表 - (時間)3.88124 - (%)55.08438
複製到tmp目錄的磁盤表 - (時間)2.683123 - (%)8.08010
轉換堆MyISAM數據 - (時間)0.37656 - (%)5.34432

這裏的講解:

id - 1 
select_type - SIMPLE 
table - linkindex_tags 
type - index 
possible_keys - link_id,link_id_2 
key - link_id 
key_len - 8 
ref - \N 
rows - 552196 
Extra - Using index; Using temporary; Using filesort 

2nd row 

id - 1 
select_type - SIMPLE 
table - links_sorted 
type - eq_ref 
possible_keys - link_id 
key - link_id 
key_len - 4 
ref - flinksdb.linkindex_tags.link_id 
rows - 1 
Extra - 

最後2表架構的:

CREATE TABLE IF NOT EXISTS `linkindex_tags` (
    `linkindex_tag_id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `link_id` int(10) unsigned NOT NULL, 
    `word_id` int(10) unsigned NOT NULL, 
    PRIMARY KEY (`linkindex_tag_id`), 
    UNIQUE KEY `link_id` (`link_id`,`word_id`), 
    KEY `link_id_2` (`link_id`), 
    KEY `word_id` (`word_id`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=0 ; 

CREATE TABLE IF NOT EXISTS `links_sorted` (
    `link_sorted_id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `site_id` int(10) unsigned NOT NULL, 
    `link_id` int(10) unsigned NOT NULL, 
    `link_title` char(255) NOT NULL, 
    `link_duration` char(20) NOT NULL, 
    `link_url` char(255) NOT NULL, 
    `active` tinyint(4) NOT NULL, 
    PRIMARY KEY (`link_sorted_id`), 
    UNIQUE KEY `link_id` (`link_id`), 
    KEY `link_title` (`link_title`,`link_url`,`active`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=0 ; 

必須堅持INT,因爲可能會進入比MEDIUMINT更大的範圍。 如果沒有連接,只需獲取ids,查詢就會很快,現在我已經提高了一些MySQL設置。

不知道MySQL設置和它們的影響太多,所以如果你需要我改變一些設置,並通過一切手段運行一些測試開火!

哦,我玩了mysql.ini設置,所以他們就是這樣 - 只是猜測和玩弄真的!

key_buffer = 512M 
max_allowed_packet = 1M 
table_cache = 512M 
sort_buffer_size = 512M 
net_buffer_length = 8K 
read_buffer_size = 512M 
read_rnd_buffer_size = 512K 

如何加快此查詢?

+0

不知道這會給你太多性能優勢,但是你可以重寫所有這些複雜的排序爲這樣的:'爲了在word_id(400,177,114,9,270,715,279,1, 1748)desc' – Karolis

+0

謝謝你,除非我錯了,不會得分比賽.. – dolyth

+0

實際上忽略了,約翰解釋這 – dolyth

回答

0

幾點意見

DISTINCT
SELECT DISTINCT適用於所有領域的選擇,無論你用多少(),用GROUP BY條款,而不是如果你只想1場是不同的。
請注意,這將使您的查詢結果不確定!
如果要防止出現這種情況,請保留該區別,或將其他字段彙總在GROUP_CONCAT中。

ORDER BY
場只能有一次在一個值,添加不同的IF的一起,當有可以匹配是浪費時間只有一個,使用一個IN代替。
布爾= 1爲真,0爲假,你不需要額外的IF來斷言。

WHERE
如果你有很多行,考慮增加一個地方,可以減少所考慮的行數,而不會改變結果。


是系列:400,177,114,9,270,715,279,1,1748相同有點像在失去了4-8-15-16-23-42神奇構建的?

SELECT lt.link_id 
    , GROUP_CONCAT(ls.link_title) as link_titles 
    , GROUP_CONCAT(ls.link_url) as link_urls 
FROM linkindex_tags lt 
INNER JOIN links_sorted ls ON ls.link_id = lt.link_id 
WHERE lt.word_id <= 1748 
GROUP BY lt.link_id 
ORDER BY 
(
    lt.word_id IN (400,177,114,9,270,715,279,1,1748) 
) DESC 
LIMIT 15 OFFSET 0; 
+0

真棒 - 越來越近。我跑了一些測試 - 不知道爲什麼你需要GROUP_CONCAT,因爲沒有它們的結果是相同的,第二個查詢執行(我猜緩存)在沒有它們的情況下更快地運行查詢。 GROUP BY(lt.link_id)不會消除這種需求嗎? - 哦,這些數字是在構建查詢時從php中放入的一系列word_id。 – dolyth

+0

如果你有多個結果ls.link_title和ls.link_url,你需要'group_concat',如果不是,那麼你不需要。對於我希望我可以在抽獎中使用他們的數字來說很糟糕。 – Johan

+0

@Dolyth,第二個查詢執行總是更快,是的,這是由於緩存。既可以緩存查詢準備和查詢結果,也可以通過使用'SELECT NO_SQL_CACHE ..查詢的其餘部分...'來禁用後者。'這樣可以在重複運行時提供更真實的結果。 – Johan