关联表查询和索引使用的探讨一则

简介:
   今天碰到一个小的查询统计需求,总结一番确实有些意思。
      在一张超多200万行的表中,需要查询在某个时段,符合全部10个类型的信息。即:
      例如某个手机号码,在某个时段完成了全部10种类型的服务。注意,决对不能使用IN操作,是全部的10个都要符合条件。同事采用中间表分步提交再查询的方法。我想是否可以用一个SQL来完成呢?且性能要好。于是“旅程”开始了。
      第一,其实这是一个比较典型的自连接操作。所以首次写了这样的SQL:

select * from 
(select distinct src_terminal_id
                  from mms_seed_info_cdr_history t
                 where to_number(t.send_time) >= to_number('20080115000000')
                   and to_number(t.send_time) <= to_number('20080331000000')
                   and t.mms_zx_id = '28') tab1,
(select distinct src_terminal_id
                  from mms_seed_info_cdr_history t
                 where to_number(t.send_time) >= to_number('20080115000000')
                   and to_number(t.send_time) <= to_number('20080331000000')
                   and t.mms_zx_id = '29') tab2,
......
                                                       tab10
where tab1.src_terminal_id = tab2.src_terminal_id
   and tab1.src_terminal_id = tab3.src_terminal_id
   ......
   and tab1.src_terminal_id = tab10.src_terminal_id;
      
      执行了很长时间,不对。停下来看,检查执行计划发现每一个嵌套的SQL都是基于全表扫描来完成查询!!注意当时的脚本中还没有使用TO_NUMBER这个函数。当时发现有时间范围搜索,立刻建立压缩索引,但是执行计划还是显示全部扫描?仔细看看,原来那个SEND_TIME字段是可空的VARCHAR2。经过询问知道实际业务中该字段是必须有值的。改不能为空,但是基于VARCHAR2的索引一旦使用大于小于这样的操作就会失效而直接使用全表扫描的。只好使用基于函数的INDEX了,于是就建立了基于TO_NUMBER(SEND_TIME)的一个索引。且另一个MMS_ZX_ID为低基数列字段,于是使用了BITMAP索引。
     查看效果,计算的执行成本基本上是原来的10%!返回首行数据的时间由26S左右,下降到6S左右了。
      开始执行,很长时间没有反馈,但是TEMP表空间却开始告急了。这个SQL基本吞噬了好几个G的空间。立刻停止!
      看上去10个表的连接ORACLE处理起来确实费力。换换方法吧。
   
select tabb1.src_terminal_id
  from (select tab1.src_terminal_id
          from (select distinct src_terminal_id
                  from mms_seed_info_cdr_history t
                 where to_number(t.send_time) >= to_number('20080115000000')
                   and to_number(t.send_time) <= to_number('20080331000000')
                   and t.mms_zx_id = '28') tab1,
               (select distinct src_terminal_id
                  from mms_seed_info_cdr_history t
                 where to_number(t.send_time) >= to_number('20080115000000')
                   and to_number(t.send_time) <= to_number('20080331000000')
                   and t.mms_zx_id = '29') tab2
         where tab1.src_terminal_id = tab2.src_terminal_id) tabb1,
......    
       (select tab9.src_terminal_id
          from (select distinct src_terminal_id
                  from mms_seed_info_cdr_history t
                 where to_number(t.send_time) >= to_number('20080115000000')
                   and to_number(t.send_time) <= to_number('20080331000000')
                   and t.mms_zx_id = '37') tab9,
               (select distinct src_terminal_id
                  from mms_seed_info_cdr_history t
                 where to_number(t.send_time) >= to_number('20080115000000')
                   and to_number(t.send_time) <= to_number('20080331000000')
                   and t.mms_zx_id = '38') tab10
         where tab9.src_terminal_id = tab10.src_terminal_id) tabb5
where tabb1.src_terminal_id = tabb2.src_terminal_id
   and tabb1.src_terminal_id = tabb3.src_terminal_id
   and tabb1.src_terminal_id = tabb4.src_terminal_id
   and tabb1.src_terminal_id = tabb5.src_terminal_id;
      
      我先将两个表连接查询嵌套成一张表,10张表我做成5个嵌套表。然后这5张表再做连接查询。看看执行效果,共执行了75S,输出结果集。
      通过这个SQL操作,我们不难看出,首先,INDEX的使用是需要讲究方式和方法的。但是可以肯定的是,一旦进行了数据类型转换操作,即使是隐性的,INDEX也会失效转而使用全部扫描了。再有就是表连接的数量,还是应该适当减少,可以通过嵌套的方式减少表连接数量,降低ORACLE内部操作复杂性,来提高执行速度。 -:)
 

      ------欢迎指正

本文转自Be the miracle!博客51CTO博客,原文链接http://blog.51cto.com/miracle/65485如需转载请自行联系原作者


Larry.Yue

相关文章
|
3月前
|
索引
15. 索引是越多越好嘛? 什么样的字段需要建索引, 什么样的字段不需要 ?
是否越多索引越好?并非如此。应根据需求建索引:主键自动索引,频繁查询、关联查询、排序、查找及统计分组字段建议建索引。但表记录少,频繁增删改操作,频繁更新的字段,以及使用频率不高的查询条件则不需要建索引。
51 0
|
2月前
|
SQL 关系型数据库 MySQL
MySQL数据库——索引(6)-索引使用(覆盖索引与回表查询,前缀索引,单列索引与联合索引 )、索引设计原则、索引总结
MySQL数据库——索引(6)-索引使用(覆盖索引与回表查询,前缀索引,单列索引与联合索引 )、索引设计原则、索引总结
46 1
|
3月前
|
存储 SQL 数据处理
什么是数据库表的索引和主索引
什么是数据库表的索引和主索引
|
9月前
|
SQL Java 关系型数据库
索引操作
索引操作
40 0
|
11月前
|
SQL 数据库 Python
根据外键倒查关联表
根据外键倒查关联表
|
关系型数据库 MySQL
MySQL查询之 如何删除主键和添加主键等修饰词
MySQL查询之 如何删除主键和添加主键等修饰词
106 0
|
存储 SQL 关系型数据库
【名词解释与区分】聚集索引、非聚集索引、主键索引、唯一索引、普通索引、前缀索引、单列索引、组合索引、全文索引、覆盖索引
【名词解释与区分】聚集索引、非聚集索引、主键索引、唯一索引、普通索引、前缀索引、单列索引、组合索引、全文索引、覆盖索引
287 1
【名词解释与区分】聚集索引、非聚集索引、主键索引、唯一索引、普通索引、前缀索引、单列索引、组合索引、全文索引、覆盖索引
|
存储 关系型数据库 MySQL
MySQL中什么是什么是主键索引、联合索引、覆盖索引、索引条件下推及区别
主键索引:它是一种特殊的唯一索引,不允许有空值,一般在建表的时候指定主键,就会创建主键索引,CREATE INDEX不能用来创建主键索引,通常使用ALTER TABLE来代替。
153 0
|
存储 SQL 关系型数据库
什么是索引覆盖?什么是索引下推?
什么是索引覆盖?什么是索引下推?
358 0
什么是索引覆盖?什么是索引下推?
|
存储 算法 搜索推荐
②MySQL的索引(普通索引、唯一索引,主键索引、组合索引、全文索引、空间索引)相关操作
MySQL的索引(普通索引、唯一索引,主键索引、组合索引、全文索引、空间索引)相关操作
256 0
②MySQL的索引(普通索引、唯一索引,主键索引、组合索引、全文索引、空间索引)相关操作