发现系统以下SQL在S1执行时间3S,但是S2上执行时间0.3S,差距很大,原因为c的子查询执行计划有问题,sql如下
SELECT
a.gather_name,
a.gender,
c.*
FROM
(SELECT
n.gather_name,
n.gather_ids,
n.gender
FROM
n
WHERE n.id = 35) a
JOIN
(SELECT DISTINCT
d.*
FROM
d
JOIN e
ON d.`category_id` = e.`category_id`
JOIN p
ON p.`goods_id` = e.`goods_id`
JOIN s
ON s.`product_id` = p.`product_id`
AND s.`stock` - s.`fix_stock` > 0
AND s.status = 1
AND e.gender IN (0, 1, 2)
ORDER BY sort DESC) c
ON INSTR(
a.gather_ids,
CONCAT(',', c.category_id, ',')
) > 0
ORDER BY c.sort ASC
S1上c子查询的执行计划:
mysql> explain SELECT DISTINCT
-> d.*
-> FROM
-> d
-> JOIN e
-> ON d.`category_id` = e.`category_id`
-> JOIN p
-> ON p.`goods_id` = e.`goods_id`
-> JOIN s
-> ON s.`product_id` = p.`product_id`
-> AND s.`stock` - s.`fix_stock` > 0
-> AND s.status = 1
-> AND e.gender IN (0, 1, 2)
-> ORDER BY sort DESC;
+----+-------------+-------+--------+-----------------------------------+------------+---------+-----------------------+--------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-----------------------------------+------------+---------+-----------------------+--------+----------------------------------------------+
| 1 | SIMPLE | e | ALL | PRIMARY,category_id,goods_id | NULL | NULL | NULL | 138326 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | d | eq_ref | PRIMARY,category_id,category_id_2 | PRIMARY | 4 | shop_zp.e.category_id | 1 | |
| 1 | SIMPLE | p | ref | PRIMARY,goods_id,product_id | goods_id | 4 | shop_zp.e.goods_id | 1 | Using index; Distinct |
| 1 | SIMPLE | s | ref | product_id | product_id | 4 | shop_zp.p.product_id | 1 | Using where; Distinct |
+----+-------------+-------+--------+-----------------------------------+------------+---------+-----------------------+--------+----------------------------------------------+
执行时间:307 rows in set (2.96 sec)
加上hint,强制执行顺序的执行计划:
mysql> explain SELECT DISTINCT
-> d.*
-> FROM
-> d
-> STRAIGHT_JOIN e
-> ON d.`category_id` = e.`category_id`
-> JOIN p
-> ON p.`goods_id` = e.`goods_id`
-> JOIN s
-> ON s.`product_id` = p.`product_id`
-> AND s.`stock` - s.`fix_stock` > 0
-> AND s.status = 1
-> AND e.gender IN (0, 1, 2)
-> ORDER BY sort DESC;
+----+-------------+-------+------+-----------------------------------+-------------+---------+-----------------------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+-----------------------------------+-------------+---------+-----------------------+------+---------------------------------+
| 1 | SIMPLE | d | ALL | PRIMARY,category_id,category_id_2 | NULL | NULL | NULL | 895 | Using temporary; Using filesort |
| 1 | SIMPLE | e | ref | PRIMARY,category_id,goods_id | category_id | 4 | shop_zp.d.category_id | 289 | Using where; Distinct |
| 1 | SIMPLE | p | ref | PRIMARY,goods_id,product_id | goods_id | 4 | shop_zp.e.goods_id | 1 | Using index; Distinct |
| 1 | SIMPLE | s | ref | product_id | product_id | 4 | shop_zp.p.product_id | 1 | Using where; Distinct |
+----+-------------+-------+------+-----------------------------------+-------------+---------+-----------------------+------+---------------------------------+
执行时间:307 rows in set (0.25 sec)
查询`information_schema`.`TABLES`,information_schema.statistics发现以下两表和实际数据有些差距
mysql> ANALYZE TABLE e;
+------------------+---------+----------+----------+
| Table | Op | Msg_type | Msg_text |
+------------------+---------+----------+----------+
| shop_zp.e | analyze | status | OK |
+------------------+---------+----------+----------+
1 row in set (0.00 sec)
mysql> ANALYZE TABLE p;
+---------------------+---------+----------+----------+
| Table | Op | Msg_type | Msg_text |
+---------------------+---------+----------+----------+
| shop_zp.p | analyze | status | OK |
+---------------------+---------+----------+----------+
1 row in set (0.01 sec)
分析后,S1的执行计划:
mysql> explain SELECT DISTINCT
-> d.*
-> FROM
-> d
-> JOIN e
-> ON d.`category_id` = e.`category_id`
-> JOIN p
-> ON p.`goods_id` = e.`goods_id`
-> JOIN s
-> ON s.`product_id` = p.`product_id`
-> AND s.`stock` - s.`fix_stock` > 0
-> AND s.status = 1
-> AND e.gender IN (0, 1, 2)
-> ORDER BY sort DESC;
+----+-------------+-------+------+-----------------------------------+-------------+---------+-----------------------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+-----------------------------------+-------------+---------+-----------------------+------+---------------------------------+
| 1 | SIMPLE | d | ALL | PRIMARY,category_id,category_id_2 | NULL | NULL | NULL | 634 | Using temporary; Using filesort |
| 1 | SIMPLE | e | ref | PRIMARY,category_id,goods_id | category_id | 4 | shop_zp.d.category_id | 206 | Using where; Distinct |
| 1 | SIMPLE | p | ref | PRIMARY,goods_id,product_id | goods_id | 4 | shop_zp.e.goods_id | 1 | Using index; Distinct |
| 1 | SIMPLE | s | ref | product_id | product_id | 4 | shop_zp.p.product_id | 1 | Using where; Distinct |
+----+-------------+-------+------+-----------------------------------+-------------+---------+-----------------------+------+---------------------------------+
此时该SQL在S1执行时间正常。
不过依然得吐槽,MySQL的统计信息和真实数据差距还是挺大!!
对MySQL统计信息了解还是不深!!待加强!!