记一条sql语句优化

 傻瓜级的。此sql语句存在于分销王系统中。

查阅slow log ,时间设置1s

发现很多

SELECT r.*, goods_id, bn, name FROM sdb_goods_rate r, sdb_goods
WHERE ((goods_2 = goods_id AND goods_1=4799) OR (goods_1 = goods_id AND goods_2 = 4799 AND manual='both')) AND rate > 99;

主要是2个表的联立,相当于inner join吧。 条件是 goods_2= xx and goods_1=zz

mysql> show create table sdb_goods_rate;
-------------------------------------------------------------------------------------+
| sdb_goods_rate | CREATE TABLE `sdb_goods_rate` (
`goods_1` mediumint(8) unsigned NOT NULL,
`goods_2` mediumint(8) unsigned NOT NULL,
`manual` enum('left','both') DEFAULT NULL,
`rate` mediumint(8) unsigned NOT NULL DEFAULT '1',
PRIMARY KEY (`goods_1`,`goods_2`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 |

可以看到goods_rate 的primary key 是 goods_1 ,goods_2 而我们用到的查询是 goods_2 ,goods_1 ,用不上我们的pk 索引。

这点可以从explain里面来观察。

mysql> explain SELECT r.*, goods_id, bn, name FROM sdb_goods_rate r, sdb_goods
-> WHERE ((goods_2 = goods_id AND goods_1=2708) OR (goods_1 = goods_id AND goods_2 = 2708 AND manual='both')) AND rate > 99;
+----+-------------+-----------+------+---------------+------+---------+------+-------+--------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+------+---------+------+-------+--------------------------------+
| 1 | SIMPLE | sdb_goods | ALL | PRIMARY | NULL | NULL | NULL | 3024 | |
| 1 | SIMPLE | r | ALL | PRIMARY | NULL | NULL | NULL | 23109 | Using where; Using join buffer |
+----+-------------+-----------+------+---------------+------+---------+------+-------+--------------------------------+

扫描都是all 全表扫描,产生了笛卡尔积,大概是 3000*23000 约等于69000000,非常大的一个数据量。

我们这里创建索引

create index idx_goods12 on sdb_goods_rate(goods_2,goods_1);

然后再看执行计划,

+----+-------------+-----------+-------------+---------------------+---------------------+---------+------+------+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------------+---------------------+---------------------+---------+------+------+----------------------------------------------------+
| 1 | SIMPLE | r | index_merge | PRIMARY,idx_goods12 | PRIMARY,idx_goods12 | 3,3 | NULL | 38 | Using sort_union(PRIMARY,idx_goods12); Using where |
| 1 | SIMPLE | sdb_goods | ALL | PRIMARY | NULL | NULL | NULL | 3024 | Range checked for each record (index map: 0x1) |
+----+-------------+-----------+-------------+---------------------+---------------------+---------+------+------+----------------------------------------------------+

数据量大大减少,为38*3024=120000,数据量规模大概小了575倍,基本上0.1秒都不用,结果就出来了。

posted @ 2013-06-30 13:23  过去的我  阅读(252)  评论(0编辑  收藏  举报