您的位置:首页 > 数据库 > MySQL

mysql利用hint的一次调优

2008-04-11 17:43 417 查看
昨天,开发人员报告,说测试机上一个sql突然变得很慢,sql如下:
select order0_.id as x0_0_
from order_tab order0_,
order_record_tab orderrecor1_,
order_factory_tab orderfacto2_,
relate_order_tab relateorde3_
where (order0_.id=orderrecor1_.order_id )
and(orderrecor1_.id=orderfacto2_.order_record_id )
and(relateorde3_.order_id=order0_.id )
and(orderfacto2_.id in(174028 , 174029))
and((relateorde3_.relate_internet_order_id is not null ))
and(relateorde3_.relate_internet_order_id not in
(select order4_.internet_order_id
from order_tab order4_,
order_record_tab orderrecor5_,
order_factory_tab orderfacto6_,
relate_order_tab relateorde7_
where (order4_.id=orderrecor5_.order_id )
and(orderrecor5_.id=orderfacto6_.order_record_id )
and(relateorde7_.order_id=order4_.id )
and(orderfacto6_.id in(174028 , 174029))
and((relateorde7_.relate_internet_order_id is not null )
)
)
);
此sql故障时的执行计划如下:
+----+--------------------+--------------+-------------+------------------------------------------------------------------------------+-----------------------------+---------+----------------------------------------+------+-------------+
|
id | select_type | table | type |
possible_keys
| key | key_len |
ref | rows | Extra |
+----+--------------------+--------------+-------------+------------------------------------------------------------------------------+-----------------------------+---------+----------------------------------------+------+-------------+
|
1 | PRIMARY | orderfacto2_ | range |
PRIMARY,ORDER_RECORD_ID
| PRIMARY | 4 |
NULL | 2 | Using where |
| 1
| PRIMARY | orderrecor1_ | eq_ref |
PRIMARY,ORDER_ID
| PRIMARY | 4 |
pointcard.orderfacto2_.ORDER_RECORD_ID | 1 | |
| 1
| PRIMARY | order0_ | eq_ref |
PRIMARY
| PRIMARY | 4 |
pointcard.orderrecor1_.ORDER_ID | 1 | Using index |
| 1
| PRIMARY | relateorde3_ | ref |
ORDER_ID,relate_order_tab_relate_internet_order_id,relate_order_tab_order_id
| relate_order_tab_order_id | 4 |
pointcard.orderrecor1_.ORDER_ID | 1 | Using where |
| 2
| DEPENDENT SUBQUERY | order4_ | ref_or_null |
PRIMARY,idx_internet_order_id,order_tab_internet_order_id
| order_tab_internet_order_id | 5 |
func | 2 | Using where |
| 2
| DEPENDENT SUBQUERY | relateorde7_ | ref |
ORDER_ID,relate_order_tab_relate_internet_order_id,relate_order_tab_order_id
| relate_order_tab_order_id | 4 |
pointcard.order4_.ID | 1 | Using where |
| 2
| DEPENDENT SUBQUERY | orderrecor5_ | ref |
PRIMARY,ORDER_ID
| ORDER_ID | 4 |
pointcard.order4_.ID | 1 | |
| 2
| DEPENDENT SUBQUERY | orderfacto6_ | ref |
PRIMARY,ORDER_RECORD_ID
| ORDER_RECORD_ID | 4 |
pointcard.orderrecor5_.ID | 1 | Using where |
+----+--------------------+--------------+-------------+------------------------------------------------------------------------------+-----------------------------+---------+----------------------------------------+------+-------------+
很显然,这是一个用hibernate生成的sql语句,执行计划显示格式比较乱。
其中,在主查询和子查询中所涉及的4个表记录数如下:
mysql> select count(1) from order_tab order0_;
+----------+
| count(1) |
+----------+
| 30737230 |
+----------+
1 row in set (0.00 sec)
mysql> select count(1) from order_record_tab orderrecor1_;
+----------+
| count(1) |
+----------+
| 31298527 |
+----------+
1 row in set (0.00 sec)
mysql> select count(1) from order_factory_tab orderfacto2_;
+----------+
| count(1) |
+----------+
| 155895 |
+----------+
1 row in set (0.00 sec)
mysql> select count(1) from relate_order_tab relateorde3_;
+----------+
| count(1) |
+----------+
| 9397 |
+----------+
1 row in set (0.00 sec)

按照sql的执行计划,主查询中先对orderfacto2_做范围扫描(range),然后和
orderrecor1_、order0_分别做等值连接(eq_ref),最后再和
relateorde3_做ref连接,这个过程是没有问题的。而子查询和主查询是完全系统的,但是子查询显然和主查询的执行计划不同,这点令人疑惑。在
生产机上此语句的执行计划如下:
+----+--------------------+--------------+--------+------------------------------------------------------------------------------+---------------------------+---------+----------------------------------------+------+-------------+
|
id | select_type | table | type |
possible_keys
| key | key_len |
ref | rows | Extra |
+----+--------------------+--------------+--------+------------------------------------------------------------------------------+---------------------------+---------+----------------------------------------+------+-------------+
|
1 | PRIMARY | orderfacto2_ | range |
PRIMARY,ORDER_RECORD_ID
| PRIMARY | 4 |
NULL | 2 | Using where |
| 1
| PRIMARY | orderrecor1_ | eq_ref |
PRIMARY,ORDER_ID
| PRIMARY | 4 |
pointcard.orderfacto2_.ORDER_RECORD_ID | 1 | |
| 1
| PRIMARY | order0_ | eq_ref |
PRIMARY
| PRIMARY | 4 |
pointcard.orderrecor1_.ORDER_ID | 1 | Using index |
| 1
| PRIMARY | relateorde3_ | ref |
ORDER_ID,relate_order_tab_relate_internet_order_id,relate_order_tab_order_id
| relate_order_tab_order_id | 4 |
pointcard.orderrecor1_.ORDER_ID | 1 | Using where |
| 2
| DEPENDENT SUBQUERY | orderfacto6_ | range |
PRIMARY,ORDER_RECORD_ID
| PRIMARY | 4 |
NULL | 2 | Using where |
| 2
| DEPENDENT SUBQUERY | orderrecor5_ | eq_ref |
PRIMARY,ORDER_ID
| PRIMARY | 4 |
pointcard.orderfacto6_.ORDER_RECORD_ID | 1 | |
| 2
| DEPENDENT SUBQUERY | order4_ | eq_ref |
PRIMARY,idx_internet_order_id,order_tab_internet_order_id
| PRIMARY | 4 |
pointcard.orderrecor5_.ORDER_ID | 1 | Using where |
| 2
| DEPENDENT SUBQUERY | relateorde7_ | ref |
ORDER_ID,relate_order_tab_relate_internet_order_id,relate_order_tab_order_id
| relate_order_tab_order_id | 4 |
pointcard.order4_.ID | 1 | Using where |
+----+--------------------+--------------+--------+------------------------------------------------------------------------------+---------------------------+---------+----------------------------------------+------+-------------+
8 rows in set (0.03 sec)

和我们意料的一样,子查询的执行计划和主查询完全相同,速度也很快。怀疑测试机上的表数据统计信息是否没有更新,但是由于analyze时间很长,此步骤暂时不能做,想到的解决办法如下:
1、使用straight join按照主查询的连接查询进行连接;
2、让开发人员修改应用,将查询分为两步,先做子查询,得到结果后再做主查询;
3、和2想法类似,不过使用临时表存储子查询结果,再做主查询。
显然,方法1是解决问题最快的方法,我们改写后的sql如下:
select order0_.id as x0_0_
from order_tab order0_,
order_record_tab orderrecor1_,
order_factory_tab orderfacto2_,
relate_order_tab relateorde3_
where (order0_.id=orderrecor1_.order_id )
and(orderrecor1_.id=orderfacto2_.order_record_id )
and(relateorde3_.order_id=order0_.id )
and(orderfacto2_.id in(174028 , 174029))
and((relateorde3_.relate_internet_order_id is not null ))
and(relateorde3_.relate_internet_order_id not in
(select order4_.internet_order_id
from
order_factory_tab orderfacto6_
STRAIGHT_JOIN
order_record_tab orderrecor5_
STRAIGHT_JOIN
order_tab order4_
STRAIGHT_JOIN
relate_order_tab relateorde7_
where
(order4_.id=orderrecor5_.order_id
)and(orderrecor5_.id=orderfacto6_.order_record_id
)and(relateorde7_.order_id=order4_.id )and(orderfacto6_.id in(174028 ,
174029))and((relateorde7_.relate_internet_order_id is not null ))));
执行计划变为:
+----+--------------------+--------------+--------+------------------------------------------------------------------------------+---------------------------+---------+----------------------------------------+------+-------------+
|
id | select_type | table | type |
possible_keys
| key | key_len |
ref | rows | Extra |
+----+--------------------+--------------+--------+------------------------------------------------------------------------------+---------------------------+---------+----------------------------------------+------+-------------+
|
1 | PRIMARY | orderfacto2_ | range |
PRIMARY,ORDER_RECORD_ID
| PRIMARY | 4 |
NULL | 2 | Using where |
| 1
| PRIMARY | orderrecor1_ | eq_ref |
PRIMARY,ORDER_ID
| PRIMARY | 4 |
pointcard.orderfacto2_.ORDER_RECORD_ID | 1 | |
| 1
| PRIMARY | order0_ | eq_ref |
PRIMARY
| PRIMARY | 4 |
pointcard.orderrecor1_.ORDER_ID | 1 | Using index |
| 1
| PRIMARY | relateorde3_ | ref |
ORDER_ID,relate_order_tab_relate_internet_order_id,relate_order_tab_order_id
| relate_order_tab_order_id | 4 |
pointcard.orderrecor1_.ORDER_ID | 1 | Using where |
| 2
| DEPENDENT SUBQUERY | orderfacto6_ | range |
PRIMARY,ORDER_RECORD_ID
| PRIMARY | 4 |
NULL | 2 | Using where |
| 2
| DEPENDENT SUBQUERY | orderrecor5_ | eq_ref |
PRIMARY,ORDER_ID
| PRIMARY | 4 |
pointcard.orderfacto6_.ORDER_RECORD_ID | 1 | |
| 2
| DEPENDENT SUBQUERY | order4_ | eq_ref |
PRIMARY,idx_internet_order_id,order_tab_internet_order_id
| PRIMARY | 4 |
pointcard.orderrecor5_.ORDER_ID | 1 | Using where |
| 2
| DEPENDENT SUBQUERY | relateorde7_ | ref |
ORDER_ID,relate_order_tab_relate_internet_order_id,relate_order_tab_order_id
| relate_order_tab_order_id | 4 |
pointcard.order4_.ID | 1 | Using where |
+----+--------------------+--------------+--------+------------------------------------------------------------------------------+---------------------------+---------+----------------------------------------+------+-------------+
8 rows in set (0.00 sec)
速度也随之变得飞快。
不过,最后应用还是按方法2进行了修改,让晦涩的语句变动更加简单、易读。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息