簡體   English   中英

MySQL聯接優化-繞過filesort

[英]MySQL join optimization - bypassing filesort

優化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                                  |
+----+-------------+-------+------+-------------------------------+-------+---------+---------------------+------+----------------------------------------------+

此版本使用正確的索引:

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列首先位於索引中),然后用於l_posts(cid, id) (同一列)。 然后它可以使用相同的索引進行排序id是索引中的下一列。 (順便說一句,這是使用MySQL優化程序的功能,該功能將where子句中的=條件從t傳播到p 。)

第二,MySQL可以將l_posts(cid, container)索引用於wherejoin 但是,那么相同的索引不能用於排序。 引擎認為文件排序比嘗試合並兩個不同的索引更好。

要獲取第二個使用索引的版本,請在l_posts(cid, container, id)上定義一個。

嘗試為第二個表添加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;

這個解決方案對我有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM