一条SQL语句的执行计划变化探究(r10笔记第9天)

继续上次分析的一个问题,一个简单的SQL语句执行计划有些奇怪,明明可以走唯一性索引但是却走了另外一个索引。
当然了,最后逐步定位,发现是在直方图的地方有一些差别。取消直方图之后,执行计划立刻恢复了正常。
当然问题来了,这个是为什么呢,收集统计信息中的auto选项是什么含义呢。为什么两个数据类型一样的(varchar2(64))的列,境遇却大大不同。
我们来看看一些统计信息的数据。

为了跟进一步验证数据的分布律和选取代价,我们查询它的直方图信息。
SQL>   select to_char(endpoint_value) value,endpoint_number,column_name from dba_tab_histograms where table_name = 'OP_ORDER' and column_name in ('ORDER_ID','USER_ID') ORDER BY endpoint_number;

可以这两条结果对应的查询结果有248行,ORDER_ID只有两行,而USER_ID却又246行,也就意味着USER_ID对应有246个bucket,对于数据的分布情况统计更为周密。
这又是为什么呢,两个字段都是varchar2,怎么会差别这么大呢。
我们取出几条数据来。
SQL> select order_id from ordermob.OP_ORDER where rownum<10;
ORDER_ID
----------------------------------------------------------------
160526163113314574
160526163122274152
160526163130777725
160526164612542552
160526172953321536
160526173306557175
160526173335364777
160526180054556153
160526180101316451
看得出来签名的很多位都是一样的,这种订单业务的数据,订单号都有一定的规范,签名的值还是有一定的规律可循。
SQL>  select to_char(endpoint_value) value,endpoint_number,column_name from dba_tab_histograms where table_name = 'OP_ORDER' and column_name in ('ORDER_ID','USER_ID') ORDER BY endpoint_number
VALUE                                    ENDPOINT_NUMBER COLUMN_NAME
---------------------------------------- --------------- ----------------------------------------
255521615291332000000000000000000000                   0 ORDER_ID
255521616530467000000000000000000000                   1 ORDER_ID
可以看到端点值(endpoint_value),endpoint_value就是列的值,非数字类型(VARCHAR2,CHAR,NVARCHAR2,NCHAR)必须进行转换,仅取前六个字节(不是字符)。从10g实测数据来看取前15个字节,前30个字符有效转换,其他都会忽略。也就是收集直方图相当于只对字段B的substr(B,1,30)收集桶信息。
这个信息怎么进行确认呢。我们取出一条数据来测试。
以max(order_id)为例,先取得dump的元数据信息。
SQL> select to_char(substrb(dump(max("ORDER_ID"),16,0,32),1,120))  from "ORDERMOB"."OP_ORDER" t ;
TO_CHAR(SUBSTRB(DUMP(MAX("ORDER_ID"),16,0,32),1,120))
------------------------------------------------------------------------------------------------------------------------
Typ=1 Len=18: 31,36,30,38,32,36,31,35,35,30,33,38,33,35,31,33,32,35
然后进行转换,转换进制。
SQL> select to_number('313630383236313535303338333531','xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx') aa from dual;
                                          AA
--------------------------------------------
        255521616530467185179705496063653169
看看这个转换后的值是否为 255521616530467,也就是转换进制后的前15位保留值。
SQL> select length('255521616530467') from dual;
LENGTH('255521616530467')
-------------------------
                       15
发现确实如此。
而整个串有36位。对于这类场景来看就很难去区分出数据的细粒度差别来。
SQL> select length('255521616530467000000000000000000000') from dual;
LENGTH('255521616530467000000000000000000000')
----------------------------------------------
                                            36
所以对于order_id的直方图信息就会只分配2个bucket,而这个过程如何验证,那就是使用经典的10046事件了。
里面的计算方式 to_char(substrb(dump(max("ORDER_ID"),16,0,32),1,120))  from "ORDERMOB"."OP_ORDER" 正式出自10046的trace文件。
当然可以自己找个环境继续验证一下。
>  create table test_stats (order_id varchar2(64),user_id varchar2(64),channel_id number);
Table created.

> insert into test_stats values('0000000000001241414','test',1);
1 row created.

> insert into test_stats values('0000000000001251414','test2',2);
1 row created.

> insert into test_stats values('0000000000001251514','test3',2);
1 row created.

> commit;
Commit complete.

生成10046事件来查看。
ALTER SESSION SET EVENTS '10046 trace name context forever, level 12'
exec dbms_stats.gather_table_stats(tabname => 'test_stats',ownname => 'TEST',method_opt => 'FOR ALL COLUMNS SIZE AUTO');
ALTER SESSION SET EVENTS '10046 trace name context off'

时间: 2024-10-24 23:07:45

一条SQL语句的执行计划变化探究(r10笔记第9天)的相关文章

一条SQL语句的执行计划变化探究

最近有个同事碰到一个问题,想让我给点思路.我大体了解了一下,是一个系统目前在做压力测试,但是经业务反馈发现某个环节的处理时间有些长,排查了一圈,最后这件事情就落在了DB这边,希望DB能够给点意见,是否存在一些性能瓶颈.     我们从开发同学那里得到的一个基本的SQL语句,根据关键字从v$sql中做了提取,发现对应的SQL语句的执行时间还是OK的. 得到的SQL语句如下:SQL_ID        SQL_FULLTEXT ------------- ----------------------

[20120104]稳定一条sql语句的执行计划.txt

[20120104]稳定一条sql语句的执行计划.txt http://www.itpub.net/thread-1495845-1-1.htmlhttp://space.itpub.net/267265/viewspace-723066 ORACLE8I升级11G R2后,查询系统视图特别慢 我的测试版本:SQL> select * from v$version where rownumBANNER------------------------------------------------

通过分析SQL语句的执行计划优化SQL(二)

优化|语句|执行 第5章 ORACLE的执行计划 背景知识:        为了更好的进行下面的内容我们必须了解一些概念性的术语: 共享sql语句    为了不重复解析相同的SQL语句(因为解析操作比较费资源,会导致性能下降),在第一次解析之后,ORACLE将SQL语句及解析后得到的执行计划存放在内存中.这块位于系统全局区域SGA(system global area)的共享池(shared buffer pool)中的内存可以被所有的数据库用户共享.因此,当你执行一个SQL语句(有时被称为一个

用C#执行SQL语句时,由于有些语句执行时间太长,在执行某一条的过程中,需要对该条语句进行标红,问怎么判断一条SQL语句正在执行中呢???

问题描述 急急急球大神指点!!!! 解决方案 解决方案二:需要对该条语句进行标红是啥意思?解决方案三:你看看这样行不行://这里执行对某行SQL语句文本设置为红色.stringinsertcommand=string.Format(@"insertintoGateChangeInfo(OldValue,NewValue,LastUpdateTime)values('{0}','{1}',{2})",TheOldGateNo.Trim(),textBox_Gate.Text.Trim()

通过分析SQL语句的执行计划优化SQL_MsSql

如何干预执行计划 - - 使用hints提示 基于代价的优化器是很聪明的,在绝大多数情况下它会选择正确的优化器,减轻了DBA的负担.但有时它也聪明反被聪明误,选择了很差的执行计划,使某个语句的执行变得奇慢无比.此时就需要DBA进行人为的干预,告诉优化器使用我们指定的存取路径或连接类型生成执行计划,从而使语句高效的运行.例如,如果我们认为对于一个特定的语句,执行全表扫描要比执行索引扫描更有效,则我们就可以指示优化器使用全表扫描.在Oracle中,是通过为语句添加hints(提示)来实现干预优化器优

通过分析SQL语句的执行计划优化SQL

如何干预执行计划 - - 使用hints提示 基于代价的优化器是很聪明的,在绝大多数情况下它会选择正确的优化器,减轻了DBA的负担.但有时它也聪明反被聪明误,选择了很差的执行计划,使某个语句的执行变得奇慢无比.此时就需要DBA进行人为的干预,告诉优化器使用我们指定的存取路径或连接类型生成执行计划,从而使语句高效的运行.例如,如果我们认为对于一个特定的语句,执行全表扫描要比执行索引扫描更有效,则我们就可以指示优化器使用全表扫描.在Oracle中,是通过为语句添加hints(提示)来实现干预优化器优

ORACLE数据库SQL语句的执行过程

SQL语句在 数据库中处理过程是怎样的呢?执行顺序呢?在回答这个问题前,我们先来回顾一下:在ORACLE数据库系统架构下,SQL语句由用户进程产生,然后传到相 对应的服务端进程,之后由服务器进程执行该SQL语句,如果是SELECT语句,服务器进程还需要将执行结果回传给用户进程. SQL语句的执行过程一般如下: 解析(PARSE)-- 绑定(BIND)--执行(EXECUTE)--提取(FETCH 只有SELECT才需要这步) 解析   服务器进程接收到一个SQL语句时,首先要将其转换成执行这个S

sql oracle-关于怎么快速执行10000条sql语句

问题描述 关于怎么快速执行10000条sql语句 由于我的数据库有几千万条数据,每一条查询都会花费0.5秒,但是10000条查询需要半个多小时,所以希望有快速一点的方法,求各位大神指点,下面是我的函数. /** * 这是一个横着的for循环,图的缩放级别是13,11*10方格,不同区域到不同区域的上车点数量 */ public static void CountListPointsOfOnetoOne() { ArrayList ListSql = new ArrayList(); double

SQL Server中如何清除特定语句的执行计划缓存

SQL server运行到一定的时候, 执行计划的缓存可能会相当大,有些能到几个GB的大小.这个时候假设某个语句比较复杂而且SQL server 生成的执行计划不够优化,你希望把该执行计划的缓存清除使得SQL server能够重新编译该语句.该如何做呢? 如果是存储过程则很好办,直接使用sp_recompile就可以了,如下所示.如果参数是表,那么所有用到该表的存储过程或http://www.aliyun.com/zixun/aggregation/17067.html">trigger都