分析案例:

1.走rule很快,但是收集了执行计划后却很慢

SQL> create table test(id int);

表已创建。

SQL> insert into test select 1 from dba_objects;

已创建49883行。

SQL> commit;

提交完成。

SQL> insert into test select 2 from user_objects where rownum<101;

已创建100行。

SQL> commit;

提交完成。

SQL> create index i_test_1 on test(id);

索引已创建。

SQL> analyze table test compute statistics;

表已分析。

SQL> set autot trace
SQL> set timing on
SQL> select * from test where id=2;

已选择100行。

已用时间:  00: 00: 00.01

执行计划
----------------------------------------------------------
Plan hash value: 1357081020

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      | 24992 | 49984 |    20  (10)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| TEST | 24992 | 49984 |    20  (10)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter("ID"=2)

统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets
         86  consistent gets
          0  physical reads
          0  redo size
       1690  bytes sent via SQL*Net to client
        451  bytes received via SQL*Net from client
          8  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
        100  rows processed

可以看出这里并没有走索引,可以对比rows和实际返回的行数100,得出这时候的统计信息并没有反应真实的情况

SQL> select /*+ rule */ * from test where id=2;

已选择100行。

已用时间:  00: 00: 00.00

执行计划
----------------------------------------------------------
Plan hash value: 3245211066

-------------------------------------
| Id  | Operation        | Name     |
-------------------------------------
|   0 | SELECT STATEMENT |          |
|*  1 |  INDEX RANGE SCAN| I_TEST_1 |
-------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - access("ID"=2)

Note
-----
   - rule based optimizer used (consider using cbo)

统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          9  consistent gets
          0  physical reads
          0  redo size
       1690  bytes sent via SQL*Net to client
        451  bytes received via SQL*Net from client
          8  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
        100  rows processed

已用时间:  00: 00: 00.01

从这里可以看出如果是走索引的话是很快的,大概已经明白了,这个字段是倾斜的,所以收集下直方图应该就能走正确的执行计划

SQL> analyze table test compute statistics for table for all indexes for all indexed columns;

表已分析。

已用时间:  00: 00: 00.37

SQL> select * from test where id=2;

已选择100行。

已用时间:  00: 00: 00.00

执行计划
----------------------------------------------------------
Plan hash value: 3245211066

-----------------------------------------------------------------------------
| Id  | Operation        | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT |          |   100 |   200 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| I_TEST_1 |   100 |   200 |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - access("ID"=2)

统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          9  consistent gets
          0  physical reads
          0  redo size
       1690  bytes sent via SQL*Net to client
        451  bytes received via SQL*Net from client
          8  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
        100  rows processed

//收集直方图后走了正确的执行计划

2.加hint也不走索引

a.隐式类型转换
 
  对于这个问题,10g可以根据执行计划下面的谓词部分来判断,而对于10g以前的版本可以根据强制加hint不走索引,
  对于index full scan和index fast full scan做为切入点

example:

执行计划
----------------------------------------------------------
Plan hash value: 4122059633

---------------------------------------------------------------------------
| Id  | Operation         | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |       |     1 |    29 |    58   (6)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| TEST1 |     1 |    29 |    58   (6)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter(TO_NUMBER("OBJECT_ID")=10000)

从这里可以看出oracle隐式的把object_id变成了number类型,强制加hint看看

1*  select /*+ index(test1) */ * from test1 where object_id=10000
SQL> /

未选定行

执行计划
----------------------------------------------------------
Plan hash value: 4122059633

---------------------------------------------------------------------------
| Id  | Operation         | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |       |     1 |    29 |    58   (6)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| TEST1 |     1 |    29 |    58   (6)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter(TO_NUMBER("OBJECT_ID")=10000)
 
确实加了hint也不走索引,既然已经知道了是因为隐式转换导致的不走索引,这时候可以有2个办法,避免隐式转换或者创建函数索引
 
  
b.索引失效

执行计划
----------------------------------------------------------
Plan hash value: 4122059633

---------------------------------------------------------------------------
| Id  | Operation         | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |       |     1 |    29 |    57   (4)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| TEST1 |     1 |    29 |    57   (4)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter("OBJECT_ID"='10000')

确认过这里的没有存在隐式类型转换,如果是10g的话,skip_unusable_indexes=true强制走索引会报错.
 检查索引的状态.

SQL> select status from user_indexes where table_name='TEST1';

STATUS
--------
UNUSABLE

索引失效了,只能rebuild,同时收集索引的统计信息,9i不要用alter index.. rebuild compute statistics;
因为这个会同时收集表的统计信息,10g以后没有问题,如果怕rebuild影响dml,那可以加上online选项

SQL> alter index i_test1_1 rebuild;

索引已更改。

SQL> analyze index i_test1_1 compute statistics;

索引已分析

SQL> set autot trace
SQL> select * from test1 where object_id='10000';

未选定行

执行计划
----------------------------------------------------------
Plan hash value: 3616871662

--------------------------------------------------------------------------------
---------

| Id  | Operation                   | Name      | Rows  | Bytes | Cost (%CPU)| T
ime     |

--------------------------------------------------------------------------------
---------

|   0 | SELECT STATEMENT            |           |     1 |    29 |     2   (0)| 0
0:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| TEST1     |     1 |    29 |     2   (0)| 0
0:00:01 |

|*  2 |   INDEX RANGE SCAN          | I_TEST1_1 |     1 |       |     1   (0)| 0
0:00:01 |

--------------------------------------------------------------------------------
---------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("OBJECT_ID"='10000')

这时候终于走索引

c.索引的访问路径oracle并没有考虑

主要讨论index fast full scan

index fast full scan类似全表扫描,只是把索引当作表来处理,支持并行和多块读
index fast full scan的前提是,索引必须满足这个查询,同时必须保证非空
(通过非空字段或者是在where条件中声明非空),最为典型的就是count(*)

SQL> create table test as select * from dba_objects;

表已创建。

SQL> create index i_test_1 on test(object_id);

索引已创建。

SQL> analyze table test compute statistics;

表已分析。

SQL> select count(*) from test;

执行计划
----------------------------------------------------------
Plan hash value: 1950795681

-------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Cost (%CPU)| Time     |
-------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     1 |   154   (2)| 00:00:02 |
|   1 |  SORT AGGREGATE    |      |     1 |            |          |
|   2 |   TABLE ACCESS FULL| TEST | 49883 |   154   (2)| 00:00:02 |
-------------------------------------------------------------------

统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets
        690  consistent gets
          0  physical reads
          0  redo size
        410  bytes sent via SQL*Net to client
        385  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

这里虽然有索引,但是oracle并不知道索引中是否有null值,所以无法走索引

SQL> select count(*) from test where object_id is not null;

执行计划
----------------------------------------------------------
Plan hash value: 1366347385

--------------------------------------------------------------------------------
--

| Id  | Operation             | Name     | Rows  | Bytes | Cost (%CPU)| Time
 |

--------------------------------------------------------------------------------
--

|   0 | SELECT STATEMENT      |          |     1 |     4 |    27   (4)| 00:00:01
 |

|   1 |  SORT AGGREGATE       |          |     1 |     4 |            |
 |

|*  2 |   INDEX FAST FULL SCAN| I_TEST_1 | 49882 |   194K|    27   (4)| 00:00:01
 |

--------------------------------------------------------------------------------
--

Predicate Information (identified by operation id):
---------------------------------------------------

2 - filter("OBJECT_ID" IS NOT NULL)

统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets
        117  consistent gets
          0  physical reads
          0  redo size
        410  bytes sent via SQL*Net to client
        385  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

select count(distinct object_id) from test;
select count(*) from (select object_id from test group by object_id);
这是itpub上的一个例子,严格来说这2个语句并不是等价的,第一个语句会忽略null,因此只要object_id上有索引
,同时索引比表小的情况就会用索引扫描代替全表扫描,而第二个语句则不会.
第一个语句和select count(*) from (select object_id from test where object_id is not null group by object_id);
是等价的.

3.统计信息不对

SQL> create table test as select * from dba_objects where 1=0;

表已创建。

SQL> analyze table test compute statistics;

表已分析。

SQL> insert into test select * from dba_objects;

已创建49920行。

SQL> commit;

提交完成。

SQL> create index i_test_1 on test(object_id);

索引已创建。

SQL> select * from test where object_id=10000;

未选定行

执行计划
----------------------------------------------------------
Plan hash value: 1357081020

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     1 |   177 |     2   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| TEST |     1 |   177 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter("OBJECT_ID"=10000)

统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets
        689  consistent gets
          0  physical reads
          0  redo size
        992  bytes sent via SQL*Net to client
        374  bytes received via SQL*Net from client
          1  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          0  rows processed

从这里来判断统计信息错误,这个表大概60000多行,这里的cost=2,rows=1(实际上这里可能是0行),基本可以判断出表是没有统计信息的,
如果这个表的统计信息是正确的话,这个表肯定是小表,一般不可能导致比较大的逻辑读

转载于:https://www.cnblogs.com/sopost/archive/2010/11/08/2190069.html

SQL 优化之该走索引却不走索引的分析相关推荐

  1. postgresql两个列模糊比较_数据分析之SQL优化系列(二)---PostgreSQL 的索引

    参考<PostgreSQL11.2-中文手册> 下面这个链接,讲的通俗易懂,可以看看. 数据分析师不得不知道的SQL优化 - 鑫获 - 博客园​www.cnblogs.com 索引是提高数 ...

  2. 不该建索引及不走索引的原因

    1.5 不应该建索引列的特点: 第一,对于那些在查询中很少使用或者参考的列不应该创建索引.这是因为,既然这些列很少使用到,因此有索引或者无索引,并不能提高查询速度.相反,由于增加了索引,反而降低了系统 ...

  3. 怎么看我装的sql能不能用_深入浅出sql优化(三)之单表索引优化

    大家好,我是闲水,每天更新java最新最热技术,对java感兴趣的朋友记得关注一下哦. 注意 :这是SQL性能优化第三章,点击关注查看前置内容. 上篇文章我们主要了解了索引优化的标尺"Exp ...

  4. oracle 优化器 失效,oracle 优化器 不走索引原因

    SQL优化器简介 基于规则的优化器 .总是使用索引 .总是从驱动表开始(from子句最右边的表) .只有在不可避免的情况下,才使用全表扫描 .任何索引都可以 基于成本的优化器 .需要表.索引的统计资料 ...

  5. 数据查询必备技能SQL调优:Mysql什么情况下不走索引

    背景分析 今天领导在查询报表时,发现特别慢,于是引发一系列关于sql优化的工作,最终发现是分析同学在进行多表关联时进行不等值关联造成全表扫描,且使用字段无索引造成1W条数据表和20W数据表关联时执行缓 ...

  6. mysql存储过程更新数据后返回一个字段_史上最全存储引擎、索引使用及SQL优化的实践...

    整个MySQL Server由以下组成 : Connection Pool :连接池组件 Management Services & Utilities :管理服务和工具组件 SQL Inte ...

  7. 数据库应用+SQL优化+Git

    数据库应用 1.1 概念 1.1.1 什么是数据库 1.1.2 关系型和非关系型 1.1.3 关系型数据库 1.2 Mysql数据库 1.2.1 MySQL数据存放在哪里? 1.2.2 MySQL服务 ...

  8. oracle 不走索引的原因

    oracle 不走索引的原因 2013-02-01 13:46  9098人阅读  评论(0)  收藏  举报   分类: oracle(27)  create table tb2 as select ...

  9. SQL优化 20 连击

    一.查询SQL尽量不要使用select *,而是具体字段 1.反例 SELECT * FROM user 2.正例 SELECT id,username,tel FROM user 3.理由 节省资源 ...

最新文章

  1. 语义分割DeepLab v2--DeepLab: Semantic Image Segmentation with Deep Convolutional Nets, Atrous Convolut
  2. Java设计模式 -- 简单工厂模式(SimpleFactory)
  3. php上传手机文件到服务器,安卓上传文件至PHP服务器(示例代码)
  4. 神经网络 | 玻尔兹曼机(附python源代码)
  5. Go 语言新提案:添加模糊测试支持
  6. Cloud for Customer UI Designer里embedded component刷新的讨论
  7. Python案例:获取全国城市列表(区号与名称)
  8. 计算机基础ppt_为什么大学老师教编程上课都不敲代码?为何老师上课都是PPT讲解,实战呢?...
  9. markdown 缩进_markdown 常用语法集合
  10. 大数据之-Hadoop3.x_MapReduce_ReduceJoin案例TableBean---大数据之hadoop3.x工作笔记0129
  11. 【一次五款】满速下载百度云神器
  12. 新pop账户服务器信息,添加 POP 账户
  13. OPNsense用户手册-基于虚拟机和云的安装
  14. 【PB】动态报表格式自由定义的实现
  15. html为知笔记模板,为知笔记如何建立模板教程
  16. Heat模板及简单应用
  17. selenium之判断是否定位正确
  18. 【小白目标检测】手把手教你做视频中的实时目标检测(基于Pelee算法)
  19. 基于FFmpeg的视频播放器之十三:抓图
  20. DB2自定义数据库方言

热门文章

  1. mock方法常用框架_什么是Mock测试?
  2. sqlite主键会加速吗_股指分歧中创下3107新高,权重主动下蹲蓄势,后市会加速吗?...
  3. react在组件内插入标签_javascript – 如何将css类添加到react中的组件?
  4. 安卓蓝牙键盘切换输入法_超薄无线蓝牙双模罗技K580键盘,自由切换享受打字快乐...
  5. 前端开发使用react实现简易路由
  6. Web前端开发基础三剑客学习知识分享
  7. web前端入门指南:来看看这位大佬的学习之路吧!
  8. 2020年面向前端开发人员的10个最佳CSS框架
  9. c linux time微秒_Linux基础知识(Linux系统、Linux中的链表)
  10. mysql -h 日志打印_mysql日志