AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 13708
Accepted
Leigh Riffel
Leigh Riffel
Asked: 2012-02-23 14:24:55 +0800 CST2012-02-23 14:24:55 +0800 CST 2012-02-23 14:24:55 +0800 CST

表统计影响仅索引查询?

  • 772

我们有一个性能不佳的查询。可以使用仅访问一个索引以从八行中检索一列(索引列)的简单查询来重现问题的根源。

该表没有统计信息,但索引有。在索引上收集新的统计数据并没有改变计划,但在表上收集统计数据却改变了。我的理解是,仅使用索引就可以满足的查询不必访问表,因此我的心智模型是表统计信息在这种情况下无关紧要,但经验似乎表明并非如此。

解释计划和自动跟踪计划都只显示索引访问,但是当表统计信息不存在时,成本和基数会显着增加。自动跟踪显示更高的 CPU、数据库时间和一致获取。我还没有尝试跟踪它,但我可以通过在表中创建/删除统计信息来重现它,如下所示。谁能解释这种行为?

set serveroutput on

DECLARE
 numr NUMBER;
 numb NUMBER;
 avgr NUMBER;
 nrow NUMBER;
 nblk NUMBER;
 numd NUMBER;
 avgl NUMBER;
 avgd NUMBER;
 cfac NUMBER;
 ilvl NUMBER;
 gues NUMBER; 
BEGIN
  --Gather Stats.
  dbms_stats.Gather_table_Stats(USER,'RESULTS');

  --Gather Index Stats.
  dbms_stats.Gather_index_Stats(USER,'I1');

  --Show Index Stats.
  dbms_stats.get_index_stats(USER, 'I1', NULL, NULL, NULL, nrow, nblk
     , numd, avgl, avgd, cfac, ilvl, NULL, gues);
  dbms_output.put_line('Number of rows: ' || TO_CHAR(nrow));
  dbms_output.put_line('Number of blocks: ' || TO_CHAR(nblk));
  dbms_output.put_line('Distinct keys: ' || TO_CHAR(numd));
  dbms_output.put_line('Avg leaf blocks/key: ' || TO_CHAR(avgl));
  dbms_output.put_line('Avg data blocks/key: ' || TO_CHAR(avgd));
  dbms_output.put_line('Clustering factor: ' || TO_CHAR(cfac));
  dbms_output.put_line('Index level: ' || TO_CHAR(ilvl));
  dbms_output.put_line('IOT guess quality: ' || TO_CHAR(gues));

  delete from plan_table;
END;
/

EXPLAIN PLAN FOR SELECT rsample_id FROM results 
   WHERE rsample_id = '0555103360';
SELECT cost, substr(lpad(' ', level-1) || operation || ' (' || options 
   || ')',1,50 ) "Operation", object_name "Object"
FROM plan_table START WITH ID = 0 CONNECT BY PRIOR id=parent_id;



DECLARE
 nrow NUMBER;
 nblk NUMBER;
 numd NUMBER;
 avgl NUMBER;
 avgd NUMBER;
 cfac NUMBER;
 ilvl NUMBER;
 gues NUMBER; 
BEGIN
  --Delete Stats.
  dbms_stats.delete_table_stats(USER,'RESULTS');

  --Gather Index Stats.
  dbms_stats.Gather_index_Stats('LRIFFEL','I1');

  --Show Index Stats.
  dbms_stats.get_index_stats(USER, 'I1', NULL, NULL, NULL, nrow, nblk
     , numd, avgl, avgd, cfac, ilvl, NULL, gues);
  dbms_output.put_line('Number of rows: ' || TO_CHAR(nrow));
  dbms_output.put_line('Number of blocks: ' || TO_CHAR(nblk));
  dbms_output.put_line('Distinct keys: ' || TO_CHAR(numd));
  dbms_output.put_line('Avg leaf blocks/key: ' || TO_CHAR(avgl));
  dbms_output.put_line('Avg data blocks/key: ' || TO_CHAR(avgd));
  dbms_output.put_line('Clustering factor: ' || TO_CHAR(cfac));
  dbms_output.put_line('Index level: ' || TO_CHAR(ilvl));
  dbms_output.put_line('IOT guess quality: ' || TO_CHAR(gues));
  delete from plan_table;
END;
/

EXPLAIN PLAN FOR SELECT rsample_id FROM results 
   WHERE rsample_id = '0555103360';
SELECT cost, substr(lpad(' ', level-1) || operation || ' (' || options 
   || ')',1,50 ) "Operation", object_name "Object"
FROM plan_table START WITH ID = 0 CONNECT BY PRIOR id=parent_id;

这有以下输出(修改以适合):

anonymous block completed
Number of rows: 125226611
Number of blocks: 381090
Distinct keys: 5778886
Avg leaf blocks/key: 1
Avg data blocks/key: 3
Clustering factor: 19792294
Index level: 3
IOT guess quality: 

plan FOR succeeded.
COST  Operation             Object                       
----- --------------------- ------
    4 SELECT STATEMENT()   
    4 INDEX (RANGE SCAN)    I1

anonymous block completed
Number of rows: 119034073
Number of blocks: 362402
Distinct keys: 5353024
Avg leaf blocks/key: 1
Avg data blocks/key: 3
Clustering factor: 18852918
Index level: 3
IOT guess quality: 

plan FOR succeeded.
COST  Operation             Object                       
----- --------------------- ------
    9 SELECT STATEMENT()   
    9 INDEX (RANGE SCAN)    I1

创建这个之后,我注意到每次运行的索引统计信息都是不同的,即使表中没有任何更改并且索引统计信息在每次运行时重新收集。我现在的理论是,在使用级联选项收集表统计信息时,即使重新收集索引统计信息,也会保留索引统计信息中的某些内容。

Granularity 设置为 AUTO,Cascade 设置为 AUTO_CASCADE。

oracle oracle-11g-r2
  • 1 1 个回答
  • 504 Views

1 个回答

  • Voted
  1. Best Answer
    Štefan Oravec
    2013-02-24T00:33:50+08:002013-02-24T00:33:50+08:00

    我猜想 CBO 以某种方式从索引统计信息计算表统计信息近似值或使用一些经验法则。

    不同的统计数据可能是由

    • dbms_stats.gather_index_stats 执行之间的 DML
    • estimate_pct 参数未设置 - 因此估计是根据样本计算的,如 Oracle 文档中所述

      estimate_percent要估计的行的百分比(NULL 表示计算)。有效范围是 [0.000001,100]。使用常量 DBMS_STATS.AUTO_SAMPLE_SIZE 让 Oracle 确定适当的样本大小以获得良好的统计信息。这是默认值。可以使用 SET_DATABASE_PREFS 过程、SET_GLOBAL_PREFS 过程、SET_SCHEMA_PREFS 过程和 SET_TABLE_PREFS 过程更改默认值。

    提示:从 Oracle 9i 开始,我们有用于格式化执行计划的 dbms_xplan 包,这可能对您的调查很有用——您可以在不同的“设置”上运行查询并查看实际使用的执行计划。检查 Oracle 文档中的dbms_xplan和一些未记录的方法,记录在此处

    • 0

相关问题

  • Oracle 中的数据库备份 - 导出数据库还是使用其他工具?

  • ORDER BY 使用文本列的自定义优先级

  • 舒服的sqlplus界面?[关闭]

  • 如何在数据库中找到最新的 SQL 语句?

  • 如何使用正则表达式查询名称?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何查看 Oracle 中的数据库列表?

    • 8 个回答
  • Marko Smith

    mysql innodb_buffer_pool_size 应该有多大?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    从 .frm 和 .ibd 文件恢复表?

    • 10 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    如何选择每组的第一行?

    • 6 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta 使用 psql 列出数据库权限 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    bernd_k 什么时候应该使用唯一约束而不是唯一索引? 2011-01-05 02:32:27 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve