记一次比较 Low 的 SQL 优化经历

第一次 SQL 如下

select *

 from ( select row_.*, rownum rownum_ 
    from (  select                   
     k18.ks1800,
     k18.ks1801,k17.ks1701,k17.ks1703,k17.ks1704,' 'as ks1503, '' as ks1504,k04.ks0403,k19.ks1904, k19.ks1905  from ks18 k18, ks17 k17, ks19 k19, ks15 k15, ks04 k04 where k18.ks1700 = k17.ks1700 and k19.ks1800 = k18.ks1800 and k19.ks1500 = k15.ks1500 and k18.ks0400 = k04.ks0400 and k17.bae001='1' and k18.bae001='1' and (k18.ks1804='1' or k18.ks1804='2') and k18.ks1805='1' and k19.bae001 = '1' and k18.ks0400 = '3d4e6569-2ea9-4d62-b8d0-bb2e1cc18c4a'  group by k18.ks1800,k18.ks1801,k17.ks1701,k17.ks1703,k17.ks1704,'', '',k04.ks0403,k19.ks1904, k19.ks1905 ) row_ where rownum <= 20) table_alias where table_alias.rownum_ > 0;

一 SQL 很慢 看看解释查询计划

一看查询计划显示,ks19 表关联时,扫描了全表,一张表 36w 数据全扫描了。这怎么行,看看是哪个条件导致的。找到相应的耗时的过滤条件行数,发现是删除标记导致的。
1
既然全表扫描了,那加个索引试试?两张表的删除标记都加上索引。
create index Index_ks19_bae001 on ks19 (bae001)
create index Index_ks17_bae001 on ks17 (bae001)
加上之后,没用,根本没有走索引,还是 Table Access Full (全表扫描)。

不对啊,才 36w 数据,就算全表扫描,只返回 20 条记录不可能这么慢啊。

二、仔细查看 SQL

我发现有 ‘’ as ks1503,‘’ as ks1504 ,group by '',''
这是什么鬼东西,说好的要什么就返回什么呢?先把这两个鬼东西去掉试试。(这里 Oracle 11g 是有查询缓存的,Mysql 已经去掉了,将Sql 和结果放入哈希表中,如果下次 Sql一样,直接返回结果,不用再去磁盘里面拿数据了,不过Mysql 已经在5.5版本之后移除了这个所谓的优化)但是 Oracle 11g 啊,查询缓存是有的,不过应该和这个不一样。因为点击下一页时,相对于来说是快的。

执行ALTER SYSTEM FLUSH SHARED_POOL;
ALTER SYSTEM FLUSH BUFFER_CACHE;
将刷新缓存
试试。去掉了一眼就看出的不必要字段,结果如下。2

好像没什么不一样的,但是好像速度快了一点(其实差不多),省去了group by 不必要的字段。

不行,再看看sql,发现关联了两张不必要的表,就是 ks04 和 ks15。这怎么能行,把不必要的关联去掉,再试试。结果从 3.6s 左右降到了 2.891s。看来不该关联的表还是不要关联,不需要的字段,还是不要返回啊。为了准确一点,我继续清缓存,继续执行语句(十次)
结果分别是
3.014s
3.185s
3.210s
3.242s
2.952s
3.042s
2.873s
2.879s
2.985s
3.032s
再看看解释查询计划
3

少关联了不必要的表,少了不必要的返回字段,扫描行数少了些,但,ks19 和 ks17 依旧是全表扫描。

这怎么办,建索引的目的就是为了避免全表扫描,导致效率太慢。
先从过滤条件入手,ks18 的 ks0400
select * from user_indexes where table_name='KS18'
看了下 这个表只有一个索引,就是主键索引,这怎么行,索引建上。
create index INDEX_KS18_KS0400 on KS18 (ks0400)
执行结果,2.421s。还行,看看解释查询计划
4
走索引了,快了一点(好像),之后的查询都在 2.4s 左右。
不错,这个索引建的没问题。
再看看 KS19 的索引
select * from user_indexes where table_name='KS19'
发现有Ks1800 的索引,但是就是不走这个,依然是 Table Access Full。既然这个显示是标志位导致全表扫描,那我把标志位删了怎样?
删了之后,再看解释查询计划6
还是全表扫描,那跟标志位没太大关系了。既然这样不行,换个思路。少关联 ks17 表,只是两张表试试怎样。结果如下
7
8
依旧全表扫描,用不到 ks19 中的 ks1800索引。我记起来了,使用索引是优化器来选择的,索引使用的流程是 先去索引数找到对应的值,在把索引树的索引对应主键给拿来,再去主键索引里面,再去取值。这种数量大的,好像全表扫描更快?每一行记录都有个 ROWID,ROWID才是真正的唯一的。
这样的话,好像数据量大的话,相当于 in 了,每一条逐条比对,不会去用索引。

这样解决全表扫描,目前来说,我是无能为力了。

小结一下

  1. 只返回需要的字段
  2. 只关联需要关联的表
  3. 给经常作为查询条件的字段加上索引,避免全表扫描

如果有人还能给出一些建议的话,感激不尽,谢谢

猜你喜欢

转载自yq.aliyun.com/articles/687976