优化一个sql,这个sql并不复杂,但执行了错误的执行计划,原始sql如下
EXPLAIN
SELECT
t1.TRANSACTION_ID,
t1.CLIENT_KEY,
t1.RING_NAME,
t1.CMS_RING_NAME,
t1.NICK_NAME,
T1.RING_TYPE,
t1.TTS_CONTENT,
T1.AUDIO_TYPE,
T1.TTS_GENDER,
T1.MSISDN,
t1.TTS_BG_MUSIC_ID,
T1.FILE_PATH,
T1.CMS_FILE_PATH,
T1.LISTEN_FILE_PATH,
T1.CONTENT_ID,
T1.COPYRIGHT_ID,
T1.REAL_COPYRIGHT_ID,
T1.STATE RING_STATE,
T1.CREATE_TIME RING_CREATE_TIME,
T2.ID,
T2.PID,
T2.TYPE STEP_TYPE,
T2.PROVINCE_CODE,
T2.LAST_TIME,
T2.STATE STEP_STATE,
T2.CREATE_TIME STEP_CREATE_TIME,
T3.CMS_CALLBACK_ID
FROM
AB_RING T1,
ab_ring_step T2,
AB_DEPLOY T3
WHERE
T1.TRANSACTION_ID = T2.TRANSACTION_ID
AND
(T2.PID = T3.STEP_ID OR T2.ID = T3.STEP_ID)
and t1.conteNT_ID='600912988981418430'
ORDER BY
T2.CREATE_TIME DESC
LIMIT 0,
10
查看执行计划
T3出现了全表扫描,会导致查询变慢,在测试数据中,各个表都只有几万条数据,耗时还不是很明显,但正式环境是上百万的数据量,这样的执行计划必然会导致慢查询。而T3表全表扫描的原因,很明显是这句话造成的
T2.PID = T3.STEP_ID OR T2.ID = T3.STEP_ID
在业务上,这句话的意思是将t2表和t3表关联,t2表如果是子流程,则将这个子流程的主流程id与t3表关联,如果t2表的数据是主流程,则直接将这个主流程与t3表关联,主流程对应的pid为‘0000000000000000000000’
根据常规优化,把or换成union all,于是sql变成了这样
EXPLAIN
SELECT
t1.TRANSACTION_ID,
t1.CLIENT_KEY,
t1.RING_NAME,
t1.CMS_RING_NAME,
t1.NICK_NAME,
T1.RING_TYPE,
t1.TTS_CONTENT,
T1.AUDIO_TYPE,
T1.TTS_GENDER,
T1.MSISDN,
t1.TTS_BG_MUSIC_ID,
T1.FILE_PATH,
T1.CMS_FILE_PATH,
T1.LISTEN_FILE_PATH,
T1.CONTENT_ID,
T1.COPYRIGHT_ID,
T1.REAL_COPYRIGHT_ID,
T1.STATE RING_STATE,
T1.CREATE_TIME RING_CREATE_TIME,
T2.ID,
T2.PID,
T2.TYPE STEP_TYPE,
T2.PROVINCE_CODE,
T2.LAST_TIME,
T2.STATE STEP_STATE,
T2.CREATE_TIME STEP_CREATE_TIME,
T3.CMS_CALLBACK_ID
FROM
AB_RING T1,
ab_ring_step T2,
AB_DEPLOY T3
WHERE
T1.TRANSACTION_ID = T2.TRANSACTION_ID
AND
T2.PID = T3.STEP_ID
AND
t1.conteNT_ID='600912988981418430'
UNION ALL
SELECT
t1.TRANSACTION_ID,
t1.CLIENT_KEY,
t1.RING_NAME,
t1.CMS_RING_NAME,
t1.NICK_NAME,
T1.RING_TYPE,
t1.TTS_CONTENT,
T1.AUDIO_TYPE,
T1.TTS_GENDER,
T1.MSISDN,
t1.TTS_BG_MUSIC_ID,
T1.FILE_PATH,
T1.CMS_FILE_PATH,
T1.LISTEN_FILE_PATH,
T1.CONTENT_ID,
T1.COPYRIGHT_ID,
T1.REAL_COPYRIGHT_ID,
T1.STATE RING_STATE,
T1.CREATE_TIME RING_CREATE_TIME,
T2.ID,
T2.PID,
T2.TYPE STEP_TYPE,
T2.PROVINCE_CODE,
T2.LAST_TIME,
T2.STATE STEP_STATE,
T2.CREATE_TIME STEP_CREATE_TIME,
T3.CMS_CALLBACK_ID
FROM
AB_RING T1,
ab_ring_step T2,
AB_DEPLOY T3
WHERE
T1.TRANSACTION_ID = T2.TRANSACTION_ID
AND
T2.ID = T3.STEP_ID
AND
t1.conteNT_ID='600912988981418430'
ORDER BY
STEP_CREATE_TIME DESC
limit 0,10
再来看看执行计划
看执行计划的最后一行,因为有order by,两个结果集合并之后需要再排序一次。排序也是相当耗时的,甚至超过全表扫描,所以这样的执行计划也是不行的。
因为T3表的step_id是有索引的,如果是 驱动表.xx = T3.step_id,这样的写法肯定是没有问题的。所以,用其他办法去掉OR查询条件,于是有了如下的sql
EXPLAIN
SELECT
t1.TRANSACTION_ID,
t1.CLIENT_KEY,
t1.RING_NAME,
t1.CMS_RING_NAME,
t1.NICK_NAME,
T1.RING_TYPE,
t1.TTS_CONTENT,
T1.AUDIO_TYPE,
T1.TTS_GENDER,
T1.MSISDN,
t1.TTS_BG_MUSIC_ID,
T1.FILE_PATH,
T1.CMS_FILE_PATH,
T1.LISTEN_FILE_PATH,
T1.CONTENT_ID,
T1.COPYRIGHT_ID,
T1.REAL_COPYRIGHT_ID,
T1.STATE RING_STATE,
T1.CREATE_TIME RING_CREATE_TIME,
T2.ID,
T2.PID,
T2.TYPE STEP_TYPE,
T2.PROVINCE_CODE,
T2.LAST_TIME,
T2.STATE STEP_STATE,
T2.CREATE_TIME STEP_CREATE_TIME,
T3.CMS_CALLBACK_ID
FROM
AB_RING T1,
(select *,
case pid
when pid='0000000000000000000000'
then ID
else pid
end xpid
from ab_ring_step) T2 ,
AB_DEPLOY T3
WHERE
T1.TRANSACTION_ID = T2.TRANSACTION_ID
AND
T2.xPID = T3.STEP_ID
AND T1.CONTENT_ID = '600912988981418430'
ORDER BY
T2.CREATE_TIME DESC
limit 0,10
再来看看执行计划
这个执行计划中,T3表方面没有什么问题了。但仍然有全表扫描,ab_ring_step表进行了全表扫描。接下来,我们优化ab_ring_step全表扫描的问题。
ab_ring_step全表扫描,会不会是因为把T2作为了一个子查询,数据放到临时表里面去了,临时表是没有索引的,所以进行了全表扫描。然而事实证明不是,为了简化这个问题,我们把sql改写为
EXPLAIN
select * from ab_ring t1,ab_ring_step t2
where t2.transaction_id = t1.transaction_id
and t1.content_id='600912988981418430'
再来看看执行计划
这回sql清晰明了,但ab_ring_step表仍然是全表扫描。有意思了,ab_ring_step表的transaction_id可是有索引的
连接条件为transaction_id的等值条件,而被驱动表ab_ring_step的transaction_id字段也是有索引,它居然走了全表扫描!
不相信,把sql反过来试试
EXPLAIN
select * from ab_ring t1,ab_ring_step t2
where t1.transaction_id = t2.transaction_id
and t2.pid='D0A956EB2D614A47BF087FD989517ACE'
执行计划
看上去没什么问题,连接条件如果在被驱动表上有索引,确实是走的索引,没毛病。
那为什么当ab_ring_step表被驱动的时候没有走索引呢?
检查N久,终于发现
两个字段的字符集不一样!
所以解决的办法就是把它们的字符集弄成一样。
再来看一看
执行计划正常了。
在看看这个sql
EXPLAIN
SELECT
t1.TRANSACTION_ID,
t1.CLIENT_KEY,
t1.RING_NAME,
t1.CMS_RING_NAME,
t1.NICK_NAME,
T1.RING_TYPE,
t1.TTS_CONTENT,
T1.AUDIO_TYPE,
T1.TTS_GENDER,
T1.MSISDN,
t1.TTS_BG_MUSIC_ID,
T1.FILE_PATH,
T1.CMS_FILE_PATH,
T1.LISTEN_FILE_PATH,
T1.CONTENT_ID,
T1.COPYRIGHT_ID,
T1.REAL_COPYRIGHT_ID,
T1.STATE RING_STATE,
T1.CREATE_TIME RING_CREATE_TIME,
T2.ID,
T2.PID,
T2.TYPE STEP_TYPE,
T2.PROVINCE_CODE,
T2.LAST_TIME,
T2.STATE STEP_STATE,
T2.CREATE_TIME STEP_CREATE_TIME,
T3.CMS_CALLBACK_ID
FROM
AB_RING T1,
(select *,
case pid
when pid='0000000000000000000000'
then ID
else pid
end xpid
from ab_ring_step) T2 ,
AB_DEPLOY T3
WHERE
T1.TRANSACTION_ID = T2.TRANSACTION_ID
AND
T2.xPID = T3.STEP_ID
AND T1.CONTENT_ID = '600912988981418430'
ORDER BY
T2.CREATE_TIME DESC
limit 0,10
执行计划
一切正常了。
那么为什么字符集不一样会导致索引失效呢?
参考这篇博客http://www.tuicool.com/articles/A7nM3yI
结论:
1.尽量避免使用or查询
2.数据库中字段的字符集一定要统一
- 大小: 13.3 KB
- 大小: 22.2 KB
- 大小: 12 KB
- 大小: 8.9 KB
- 大小: 15.8 KB
- 大小: 9.6 KB
- 大小: 39.9 KB
- 大小: 30.3 KB
- 大小: 16 KB
- 大小: 12.6 KB
分享到:
相关推荐
- 尽可能避免在WHERE子句中使用`OR`,因为它可能导致索引失效。 - 使用内连接(INNER JOIN)代替子查询,以提高性能。 4. **使用分区:** - 对于大型表,可以通过分区来提高查询性能。 - 分区可以基于日期、范围...
- **问题描述**:使用 `LIKE '%parm1%'` 的查询方式会导致索引失效,降低查询效率。 - **解决方案**: - **前端改进**:改变用户输入方式,比如采用下拉列表选择供应商,减少模糊查询的需求。 - **后端改进**:...
索引是SQL优化的基础技术之一,索引可以加速查询速度、提高数据检索效率。常见的索引类型有: 1. 普通索引(Normal Index) 2. 位图索引(Bitmap Index) 3. 唯一索引(Unique Index) 4. 函数索引(Function-based...
#### 一、Oracle SQL优化的重要性 在系统开发初期,由于数据库数据量较小,可能不会明显感受到不同SQL语句编写方式带来的性能差异。然而,当系统投入实际应用,尤其是面对海量数据时,SQL语句的优化就显得尤为重要...
以下是对标题和描述中提及的SQL优化技巧的详细说明: 1. **建立索引**:索引可以显著提高查询速度,尤其是在WHERE子句和ORDER BY子句涉及的列上。创建合适的索引可以避免全表扫描,提高查询效率。 2. **避免NULL值...
=`)可能会导致索引失效。 - **优化建议**: - 尽量使用等值比较(`=`),因为大多数情况下数据库引擎可以利用索引来加速查询。 - 如果确实需要使用不等于运算符,考虑使用`NOT IN`、`NOT EXISTS`等替代方案。 ### ...
此外,LIKE操作符配合百分号(%)在前的模式匹配、OR条件中部分列未索引、非等值比较以及对字符串列未使用引号等情况,都可能导致索引失效。 在创建索引时,应考虑查询的常见模式,通常复合索引适用于多条件查询,...
### SQL优化大全 #### 1. 优化 WHERE 子句中的 ORDER BY 和其他过滤条件 在 SQL 查询中,WHERE 子句与 ORDER BY 子句的优化是非常重要的。如果 WHERE 子句中包含 ORDER BY 或其他过滤条件,应尽可能地进行优化以...
### 基于Mysql数据库的SQL优化 #### 一、表结构设计原则与存储引擎选择 ##### 1.1 表结构设计原则 - **选择合适的数据类型**:尽量选择固定长度的数据类型,例如使用`INT`而非`VARCHAR`来存储数字型数据,这有助...
**描述:** 使用OR连接条件可能导致索引失效,尤其是在多个条件之间使用OR时。通过使用UNION ALL来组合多个SELECT语句,可以更好地利用索引。 **扩展知识点:** - **UNION与UNION ALL的区别**: UNION用于合并两个结果...
### SQL优化建议与MySQL性能调优 #### 一、避免使用`SELECT *` - **推荐做法**:在执行查询时,指定所需的特定字段而非使用`SELECT *`。 - **反例**:`SELECT * FROM employee;` - **正例**:`SELECT id, name ...
3. 使用or连接查询条件会使得查询优化器放弃使用索引。如果需要使用多个查询条件,应该分别对每个条件执行查询,然后通过union all语句将结果集合并起来。 4. 在where子句中使用in操作符时,如果参数列表中的值较多...
4. **慎用OR连接条件**:多个`OR`条件可能导致索引失效。推荐使用多个查询语句并用`UNION ALL`合并结果。 5. **合理使用IN和NOT IN**:使用`IN`或`NOT IN`可能导致全表扫描,特别是当列表很长时。对于连续的数值...
### Oracle SQL优化详解 #### 一、SQL语句编写注意事项 **1. ISNULL与ISNOTNULL** 在WHERE子句中使用`IS NULL`或`IS NOT NULL`时,Oracle优化器通常不会利用索引进行搜索。这是因为`IS NULL`和`IS NOT NULL`检查的...
### Java数据库之SQL优化 #### 一、导致SQL慢的原因 1. **硬件问题**:主要包括网络速度慢、I/O速度慢、内存不足、吞吐量低、磁盘空间满等因素。这些问题通常会导致数据处理速度下降,从而影响SQL查询的速度。 2. ...
11. **避免OR条件连接**:OR可能导致索引失效,考虑使用UNION ALL替代。 12. **避免在WHERE子句中进行表达式操作或函数操作**:如除法、函数(如DATE_FORMAT)等,这些都会导致索引失效。 13. **LIKE操作符的使用*...
对列进行操作(如计算、函数处理等)会使得索引失效,应尽量避免在WHERE子句中使用这些操作。 - **第二掌:防止不必要的类型转换** 类型转换可能导致索引无法有效使用,确保数据类型匹配可提高查询效率。 - **...
"IN"和"OR"操作可能导致索引失效,尽量转换为等值连接,或者使用UNION替换,以利用索引。 5. **第五掌:避免"<>"** "<>"操作符通常不能利用索引,可以尝试转换为NOT=或其他方式。 6. **第六掌:去掉 WHERE 子句...
- **查询重构**:避免在JOIN条件中使用非索引列,减少索引失效情况。 - **物化视图**:对于固定的复杂查询,创建物化视图可提前计算结果,提高查询速度。 - **索引覆盖**:确保查询所需的所有列都在索引中,以...