2013-05-19 94 views
0

我正在開發一個基於XenForo引擎的網站,並且在查詢中存在一個問題,該查詢獲取所有線程和連接張貼表和論壇表以獲取第一篇文章和論壇的一些信息線程屬於。查詢看起來像:大量行的MySQL性能問題

SELECT thread . *
FROM xf_thread AS thread
INNER JOIN xf_node AS node ON (node.node_id = thread.node_id)
INNER JOIN xf_post AS post ON (post.post_id = thread.first_post_id)
WHERE thread.node_id IN ('295', '296', '297', '298', '299', '300', '301', '302', '256', '2575', '258', '259', '260', '253', '254', '255', '127', '163', '159', '144', '145', '146', '147', '148', '164', '165', '166', '167', '168', '169', '170', '162', '171', '173', '172', '128', '129', '130', '131', '132', '133', '134', '135', '136', '137', '138', '139', '140', '141', '142', '143', '151', '152', '153', '154', '155', '157', '156', '158', '161', '160', '149', '227', '232', '237', '233', '236', '234', '235', '238', '248', '240', '241', '242', '239', '246', '247', '243', '244', '245', '228', '229', '230', '231', '249', '250', '251', '174', '190', '195', '199', '193', '191', '197', '198', '192', '200', '204', '207', '205', '203', '206', '202', '208', '201', '187', '176', '177', '178', '189', '188', '180', '186', '184', '185', '182', '183', '181', '179', '209', '211', '217', '218', '219', '210', '212', '213', '214', '215', '216', '220', '222', '223', '224', '221', '225', '261', '291', '276', '272', '270', '265', '277', '267', '286', '292', '289', '274', '264', '287', '278', '282', '279', '281', '280', '283', '284', '285', '290', '275', '268', '263', '266', '294', '262', '293', '269', '273', '288', '271')
ORDER BY thread.last_post_date DESC
LIMIT 10

解釋查詢的結果是:

 
id select_type table type possible_keys key key_len ref rows Extra 
1 SIMPLE node index PRIMARY PRIMARY 4 NULL 199 Using where; Using index; Using temporary; Using filesort 
1 SIMPLE thread ref node_id_last_post_date,node_id_sticky_last_post_date node_id_last_post_date 4 node.node_id 221 
1 SIMPLE post eq_ref PRIMARY PRIMARY 4 thread.first_post_id 1 Using index

查詢需要9+秒來執行。

刪除加入xf_node表,在0.01秒內運行查詢。解釋貌似

id select_type table type possible_keys key key_len ref rows Extra 
1 SIMPLE thread index node_id_last_post_date,node_id_sticky_last_post_da... last_post_date 4 NULL 69970 Using where 
1 SIMPLE post eq_ref PRIMARY PRIMARY 4 thread.first_post_id 1 Using index

刪除xf_post表的連接運行在0.01秒內查詢,解釋貌似

id select_type table type possible_keys key key_len ref rows Extra 
1 SIMPLE thread index node_id_last_post_date,node_id_sticky_last_post_da... last_post_date 4 NULL 70840 Using where 
1 SIMPLE node eq_ref PRIMARY PRIMARY 4 thread.node_id 1 Using index

因此,只有當兩個表的連接問題的存在,但聯接本身似乎是完全正確和完全分開工作。

表中的行數 - xf_thread:71855,xf_node:178,xf_post:2977326

我的假設是,當兩個表的連接的MySQL開始使用不正確的索引,並可能迫使指數將解決問題?

您的幫助和建議,以找到一種方法來解決這個問題,高度讚賞。

編輯:下面是CREATE TABLE語句中的所有表涉案

xf_node

CREATE TABLE `xf_node` ( 
    `node_id` int(10) unsigned NOT NULL auto_increment, 
    `title` varchar(50) NOT NULL, 
    `description` text NOT NULL, 
    `node_name` varchar(50) default NULL COMMENT 'Unique column used as string ID by some node types', 
    `node_type_id` varbinary(25) NOT NULL, 
    `parent_node_id` int(10) unsigned NOT NULL default '0', 
    `display_order` int(10) unsigned NOT NULL default '1', 
    `display_in_list` tinyint(3) unsigned NOT NULL default '1' COMMENT 'If 0, hidden from node list. Still counts for lft/rgt.', 
    `lft` int(10) unsigned NOT NULL default '0' COMMENT 'Nested set info ''left'' value', 
    `rgt` int(10) unsigned NOT NULL default '0' COMMENT 'Nested set info ''right'' value', 
    `depth` int(10) unsigned NOT NULL default '0' COMMENT 'Depth = 0: no parent', 
    `style_id` int(10) unsigned NOT NULL default '0' COMMENT 'Style override for specific node', 
    `effective_style_id` int(10) unsigned NOT NULL default '0' COMMENT 'Style override; pushed down tree', 
    PRIMARY KEY (`node_id`), 
    UNIQUE KEY `node_name_unique` (`node_name`,`node_type_id`), 
    KEY `parent_node_id` (`parent_node_id`), 
    KEY `display_order` (`display_order`), 
    KEY `display_in_list` (`display_in_list`,`lft`), 
    KEY `lft` (`lft`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=304 ; 

xf_post

CREATE TABLE `xf_post` ( 
    `post_id` int(10) unsigned NOT NULL auto_increment, 
    `thread_id` int(10) unsigned NOT NULL, 
    `user_id` int(10) unsigned NOT NULL, 
    `username` varchar(50) NOT NULL, 
    `post_date` int(10) unsigned NOT NULL, 
    `message` mediumtext NOT NULL, 
    `ip_id` int(10) unsigned NOT NULL default '0', 
    `message_state` enum('visible','moderated','deleted') NOT NULL default 'visible', 
    `attach_count` smallint(5) unsigned NOT NULL default '0', 
    `position` int(10) unsigned NOT NULL, 
    `likes` int(10) unsigned NOT NULL default '0', 
    `like_users` blob NOT NULL, 
    `warning_id` int(10) unsigned NOT NULL default '0', 
    `warning_message` varchar(255) NOT NULL default '', 
    PRIMARY KEY (`post_id`), 
    KEY `thread_id_post_date` (`thread_id`,`post_date`), 
    KEY `thread_id_position` (`thread_id`,`position`), 
    KEY `user_id` (`user_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=3123657 ; 

xf_thread

CREATE TABLE `xf_thread` ( 
    `thread_id` int(10) unsigned NOT NULL auto_increment, 
    `node_id` int(10) unsigned NOT NULL, 
    `title` varchar(150) NOT NULL, 
    `reply_count` int(10) unsigned NOT NULL default '0', 
    `view_count` int(10) unsigned NOT NULL default '0', 
    `user_id` int(10) unsigned NOT NULL, 
    `username` varchar(50) NOT NULL, 
    `post_date` int(10) unsigned NOT NULL, 
    `sticky` tinyint(3) unsigned NOT NULL default '0', 
    `discussion_state` enum('visible','moderated','deleted') NOT NULL default 'visible', 
    `discussion_open` tinyint(3) unsigned NOT NULL default '1', 
    `discussion_type` varchar(25) NOT NULL default '', 
    `first_post_id` int(10) unsigned NOT NULL, 
    `first_post_likes` int(10) unsigned NOT NULL default '0', 
    `last_post_date` int(10) unsigned NOT NULL, 
    `last_post_id` int(10) unsigned NOT NULL, 
    `last_post_user_id` int(10) unsigned NOT NULL, 
    `last_post_username` varchar(50) NOT NULL, 
    `prefix_id` int(10) unsigned NOT NULL default '0', 
    PRIMARY KEY (`thread_id`), 
    KEY `node_id_last_post_date` (`node_id`,`last_post_date`), 
    KEY `node_id_sticky_last_post_date` (`node_id`,`sticky`,`last_post_date`), 
    KEY `last_post_date` (`last_post_date`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=76301 ; 

謝謝。

+0

你可以做它的兩個查詢。首先獲取'thred'與'post'連接並在第二個'select * from xf_node WHERE node_id IN(從第一個查詢中節點列表)' – piotrekkr

+0

這個問題似乎更適合[dba.se]。投票遷移它。 –

+0

@piotrekkr這個查詢是由XenForo使用它的模型生成的,所以拆分成單獨的查詢不是我的選擇 –

回答

0

有時mysql中的order by子句將使用臨時表對結果進行排序。對於大數據可能需要很長時間。避免使用「通過desc命令」和MySQL以外的數據排序。

+0

不幸的是,在PHP中訂購是一個選項,因爲在沒有訂購的情況下返回了70 000多個線程。謝謝。 –

0

您發佈的查詢不會使用帖子表中的任何列,也不會在過濾器中使用。我會說你可以放棄。

對於降序排序(這是耗時):如果你創建了一個附加列,並與

MAX_INT - unix_timestamp(thread.last_post_date) 

這會給你以後的線程數量較少填充它,可以進行調整成ASC,所以一個ASC順序就能讓你真正按時完成DESC。

在這種情況下,還必須創建新的索引。

(這個例子是僞語言,檢查語法的MySQL)

+0

謝謝你的建議。該查詢實際上是使用來自兩個表的數據,以及更多的表和字段,我剛剛發佈了簡化版本,以表明即使簡單的連接本身也會導致問題。按照您的建議進行排序的想法可能會有所幫助,但對我來說這不是一個全局解決方案,因爲我不是在編寫查詢本身,而是使用XenForo模型來獲取此數據,並且此查詢由系統生成,我不想改變。 –

0

如果兩個thread列(node_idfirst_post_id)不可爲空,你有FOREIGN KEY的約束,你可以信任,從thread(node_id)xf_node (node_id)thread(first_post_id)xf_post(post_id),你可以刪除加入到xf_nodexf_post

SELECT thread . * 
FROM xf_thread AS thread 
WHERE thread.node_id IN (295, 296, ..., 271) 
ORDER BY thread.last_post_date DESC 
LIMIT 10 ; 

上索引0可能有所幫助,以提高工作效率:

ALTER TABLE xf_thread 
    ADD INDEX last_post_date_node_id 
    (last_post_date, node_id) ; 
+0

不幸的是,在XenForo表中沒有定義外鍵,並且已經有一個包含last_post_date和node_id所有列的索引。謝謝。 –

+0

如果您在問題中添加了「CREATE TABLE」語句,這將有所幫助。所以我們知道數據類型,索引和引擎。 –

+0

現在編輯問題幷包括創建表statemnets。謝謝。 –

0

莫比嘗試這樣的事情之一,顯示評論結果:

SELECT thread . *, post.* 
FROM xf_thread AS thread 
INNER JOIN xf_node AS node ON (node.node_id = thread.node_id)  
JOIN (
    SELECT * 
    FROM xf_post AS p 
    WHERE p.post_id IN (
     SELECT t.first_post_id FROM thread t WHERE t.node_id IN ('295', ...) 
    ) 
) AS post ON thread.first_post_id = post.post_id 
WHERE thread.node_id IN ('295', ...) 
ORDER BY thread.last_post_date DESC 
LIMIT 10 
+0

我已經試過這個查詢,它非常耗費資源,只需掛上MySQL服務器 –