仍然在优化MySQL LEFT JOIN时遇到问题。该查询需要0.13秒才能完成而不是0.00(下一个(简化版))。
我想为该查询达到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 | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+-------------------+-------+---------+---------------------+------+----------------------------------------------+ | 1 | SIMPLE | t | ref | PRIMARY,cid,cid_2 | cid | 4 | const | 216 | Using index; Using temporary; Using filesort | | 1 | SIMPLE | p | ref | PRIMARY,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 | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+-------------------+---------+---------+-------+-------+--------------------------+ | 1 | SIMPLE | p | range | PRIMARY,cid,cid_2 | PRIMARY | 4 | NULL | 31720 | Using where; Using index | | 1 | SIMPLE | t | ref | PRIMARY,cid,cid_2 | cid_2 | 4 | const | 194 | Using index | +----+-------------+-------+-------+-------------------+---------+---------+-------+-------+--------------------------+
表:
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
这是戈登指数补充后的EXPLAIN输出:
+----+-------------+-------+------+-------------------------------+-------+---------+---------------------+------+----------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+-------------------------------+-------+---------+---------------------+------+----------------------------------------------+ | 1 | SIMPLE | t | ref | PRIMARY,cid,cid_2 | cid | 4 | const | 212 | Using index; Using temporary; Using filesort | | 1 | SIMPLE | p | ref | PRIMARY,cid,cid_2,cid_3,cid_4 | cid_3 | 8 | const,forumdb.t.id | 11 | Using index | +----+-------------+-------+------+-------------------------------+-------+---------+---------------------+------+----------------------------------------------+
答案 0 :(得分: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
是索引中的下一列。 (顺便说一下,这是使用MySQL优化器的一个功能,它将=
条件中的where
条件从t
传播到p
。)
对于第二个,MySQL可以使用l_posts(cid, container)
和where
的{{1}}索引。但是,相同的索引不能用于排序。引擎决定文件排序比尝试合并两个不同的索引更好。
要使第二个版本使用索引,请在join
上定义一个。
答案 1 :(得分:0)
尝试为第二个表添加WHERE条件:
SELECT
SQL_NO_CACHE p.id
FROM
1_posts p
INNER JOIN 1_topics t
ON (p.cid = t.cid)
WHERE
t.cid = 1010699 AND p.id > 0
ORDER BY
p.id DESC
LIMIT 1;
这个解决方案对我有用。