0

XenForo エンジンに基づいてサイトを開発していますが、すべてのスレッドをフェッチし、投稿テーブルとフォーラム テーブルを結合してスレッドが属する最初の投稿とフォーラムの情報を取得するクエリに問題があります。クエリは次のようになります。

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

クエリの Explain 結果は次のとおりです。

id select_type テーブル タイプ possible_keys キー key_len ref 行 エクストラ
1 SIMPLE ノード インデックス PRIMARY PRIMARY 4 NULL 199 where; の使用。インデックスの使用; 一時的な使用; ファイルソートの使用
1 SIMPLE スレッド参照 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 インデックスの使用

クエリの実行には 9 秒以上かかります。

xf_node テーブルの結合を削除すると、クエリは 0.01 秒で実行されます。説明は次のようになります

id select_type テーブル タイプ possible_keys キー key_len ref 行 エクストラ
1 SIMPLE スレッド インデックス node_id_last_post_date,node_id_sticky_last_post_da... last_post_date 4 NULL 69970 where の使用
1 SIMPLE post eq_ref PRIMARY PRIMARY 4 thread.first_post_id 1 インデックスの使用

xf_post テーブルの結合を削除すると、クエリは 0.01 秒で実行されます。説明は次のようになります。

id select_type テーブル タイプ possible_keys キー key_len ref 行 エクストラ
1 SIMPLE スレッド インデックス node_id_last_post_date,node_id_sticky_last_post_da... last_post_date 4 NULL 70840 where の使用
1 SIMPLE node eq_ref PRIMARY PRIMARY 4 thread.node_id 1 インデックスを使用

したがって、問題は両方のテーブルが結合されている場合にのみ存在しますが、結合自体は完全に正しく、完全に個別に機能するようです。

テーブル内の行数 - xf_thread: 71,855、xf_node: 178、xf_post: 2,977,326

私の推測では、両方のテーブルが結合されると、MySQL は不適切なインデックスを使用し始め、インデックスを強制することで問題が解決するのでしょうか?

この問題を解決する方法を見つけるためのあなたの助けと提案は非常に高く評価されています.

編集:関係するすべてのテーブルのテーブル作成ステートメントは次のとおりです

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 ;  

ありがとうございました。

4

4 に答える 4

0

場合によっては、mysql の order by 句で一時テーブルを使用して結果を並べ替えます。大きなデータの場合、かなりの時間がかかる場合があります。"order by desc" の使用を避け、mysql の外部でデータをソートします。

于 2013-05-19T07:54:08.477 に答える
0

投稿したクエリは、投稿テーブルの列を使用しておらず、フィルターでも使用されていません。私はあなたがそれを落とすことができると言います。

DESC の順序付け (時間がかかる) の場合: 追加の列を作成して、次のように入力すると、ASC に微調整できます。

MAX_INT - unix_timestamp(thread.last_post_date)

これにより、後のスレッドの数値が小さくなるため、ASC 注文は実際に時間通りに DESC を提供します。

その場合、新しいインデックスも作成する必要があります。

(例は疑似言語です。構文については mysql を確認してください)

于 2013-05-19T08:25:29.010 に答える