1

MySQL LEFT JOIN の最適化にまだ問題があります。そのクエリは、次の 0.00 秒 (単純化されたもの) ではなく、完了するのに 0.13 秒かかります。

そのクエリで 0.00 程度を達成したいと思います。

インデックスとコンボインデックスを作成しようとしました。あまり変わりません。基本的に EXPLAIN に FILESORT がある限り遅いです。何をすればよいかわかりません...テーブル全体にインデックスを作成しますか? それは存在しますか?

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

犯人:

SELECT 
  SQL_NO_CACHE p.id 
FROM 1_posts p 
  INNER JOIN 1_topics t 
    ON (p.cid = t.cid && p.container = t.id) 
WHERE 
  t.cid = 1010699 
ORDER BY 
  p.id DESC 
LIMIT 1;

EXPLAIN 出力:

+----+-------------+-------+------+--------------- --+------+---------+---------------------+----- -------------------------------------------------+
| | ID | select_type | テーブル | タイプ | 可能な_キー | キー | key_len | 参照 | 行 | 行 エクストラ |
+----+-------------+-------+------+--------------- --+------+---------+---------------------+----- -------------------------------------------------+
| | 1 | シンプル | t | 参照 | プライマリ,cid,cid_2 | シド | 4 | 定数 | 216 | インデックスの使用; 一時的な使用; ファイルソートの使用 |
| | 1 | シンプル | p | 参照 | プライマリ,cid,cid_2 | cid_2 | 8 | const,forumdb.t.id | 12 | | |
+----+-------------+-------+------+--------------- --+------+---------+---------------------+----- -------------------------------------------------+

さて、正常に動作する同じ単純化されたクエリ (インデックスなどを使用します。唯一の違いは括弧の間です):

SELECT 
  SQL_NO_CACHE p.id 
FROM 
  1_posts p 
  INNER JOIN 1_topics t 
    ON (p.cid = t.cid) 
WHERE 
  t.cid = 1010699 
ORDER BY 
  p.id DESC 
LIMIT 1;

説明:

+----+-------------+-------+-------+-------------- ---+---------+---------+-------+-------+-------- ------------------+
| | ID | select_type | テーブル | タイプ | 可能な_キー | キー | key_len | 参照 | 行 | 行 エクストラ |
+----+-------------+-------+-------+-------------- ---+---------+---------+-------+-------+-------- ------------------+
| | 1 | シンプル | p | 範囲 | プライマリ,cid,cid_2 | プライマリ | 4 | ヌル | 31720 | where を使用します。インデックスの使用 |
| | 1 | シンプル | t | 参照 | プライマリ,cid,cid_2 | cid_2 | 4 | 定数 | 194 | インデックスの使用 |
+----+-------------+-------+-------+-------------- ---+---------+---------+-------+-------+-------- ------------------+

テーブル:

CREATE TABLE `1_posts` (
  `cid` int(20) unsigned NOT NULL DEFAULT '0',
  `id` int(20) unsigned NOT NULL AUTO_INCREMENT,
  `container` int(20) unsigned NOT NULL DEFAULT '0',
  `creator` int(20) unsigned NOT NULL DEFAULT '0',
  `ref` int(20) unsigned DEFAULT NULL,
  `timestamp` int(20) unsigned NOT NULL DEFAULT '0',
  `posticon` tinyint(11) DEFAULT NULL,
  `last_edited_ts` int(10) unsigned DEFAULT NULL,
  `last_edited_by` int(20) unsigned DEFAULT NULL,
  `signature` varchar(250) DEFAULT NULL,
  `client_ip` int(10) unsigned NOT NULL DEFAULT '0',
  `data_format` tinyint(20) unsigned DEFAULT NULL,
  `use_bbcode` tinyint(3) unsigned NOT NULL DEFAULT '1',
  `use_smileys` tinyint(3) unsigned NOT NULL DEFAULT '1',
  `topic_hash` int(10) unsigned NOT NULL DEFAULT '0',
  `del_ts` int(10) unsigned NOT NULL DEFAULT '0',
  `del_reason` tinyint(4) NOT NULL DEFAULT '0',
  PRIMARY KEY (`cid`,`id`),
  UNIQUE KEY `cid` (`cid`,`topic_hash`,`container`,`id`,`del_ts`),
  KEY `cid_2` (`cid`,`container`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8


CREATE TABLE `1_topics` (
  `cid` int(10) unsigned NOT NULL DEFAULT '0',
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `container` int(20) NOT NULL DEFAULT '0',
  `name` varchar(128) NOT NULL DEFAULT '',
  `creator` int(20) unsigned NOT NULL DEFAULT '0',
  `last_modified` int(20) unsigned NOT NULL DEFAULT '0',
  `views` int(11) NOT NULL DEFAULT '0',
  `closed` tinyint(3) unsigned NOT NULL DEFAULT '0',
  `sticky` tinyint(3) unsigned NOT NULL DEFAULT '0',
  `last_post_id` int(20) unsigned DEFAULT NULL,
  `num_posts` int(10) unsigned DEFAULT NULL,
  `lp_ts` int(20) unsigned NOT NULL DEFAULT '0',
  `posticon` smallint(5) unsigned DEFAULT NULL,
  `hidden` tinyint(3) unsigned NOT NULL DEFAULT '0',
  `topic_change_ts` int(10) unsigned NOT NULL DEFAULT '0',
  `topic_hash` int(10) unsigned NOT NULL DEFAULT '0',
  `forum_hash` int(10) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`cid`,`id`),
  KEY `container` (`container`),
  KEY `last_modified` (`last_modified`),
  KEY `sticky` (`sticky`),
  KEY `topic_hash` (`topic_hash`),
  KEY `forum_hash` (`forum_hash`),
  KEY `cid` (`cid`,`id`),
  KEY `cid_2` (`cid`),
  FULLTEXT KEY `name` (`name`)
) ENGINE=MyISAM AUTO_INCREMENT=211963 DEFAULT CHARSET=latin1

これは、Gordon のインデックスが追加された後の EXPLAIN 出力です。

+----+-------------+-------+------+--------------- ----+---------------------+---------------------+--------------- ------+--------------------+------------------------------------ ----------+
| | ID | select_type | テーブル | タイプ | 可能な_キー | キー | key_len | 参照 | 行 | 行 エクストラ |
+----+-------------+-------+------+--------------- ----+---------------------+---------------------+--------------- ------+--------------------+------------------------------------ ----------+
| | 1 | シンプル | t | 参照 | プライマリ,cid,cid_2 | シド | 4 | 定数 | 212 | インデックスの使用; 一時的な使用; ファイルソートの使用 |
| | 1 | シンプル | p | 参照 | PRIMARY,cid,cid_2,cid_3,cid_4 | cid_3 | 8 | const,forumdb.t.id | 11 | インデックスの使用 |
+----+-------------+-------+------+--------------- ----+---------------------+---------------------+--------------- ------+--------------------+------------------------------------ ----------+
4

2 に答える 2

2

このバージョンでは正しいインデックスを使用しています:

SELECT SQL_NO_CACHE p.id
FROM 1_posts p INNER JOIN
     1_topics t
     ON (p.cid = t.cid)
WHERE t.cid = 1010699
ORDER BY p.id DESC LIMIT 1;

このバージョンは以下を行いません:

SELECT SQL_NO_CACHE p.id
FROM 1_posts p INNER JOIN
     1_topics t
     ON (p.cid = t.cid && p.container = t.id);
WHERE t.cid = 1010699
ORDER BY p.id DESC
LIMIT 1;

最初に、MySQL はl_posts(cid, id)最初にwhere句 (cid列はインデックスの最初) に、次に結合 (同じ列) にインデックスを使用できます。次に、並べ替えに同じインデックスを使用できます。これidは、インデックスの次の列です。(ちなみに、これはfrom to節の=条件を伝播する MySQL オプティマイザの機能を使用しています。)wheretp

次に、MySQL はおよびのl_posts(cid, container)インデックスを使用できます。ただし、同じインデックスを並べ替えに使用することはできません。エンジンは、2 つの異なるインデックスをマージしようとするよりも、ファイル ソートの方が優れていると判断します。wherejoin

2 番目のバージョンでインデックスを使用するには、 で 1 つ定義しl_posts(cid, container, id)ます。

于 2013-08-13T10:47:55.533 に答える