第2章 统计信息
2.1 什么是统计信息
前面提到,只有大表才会产生性能问题,那么怎么才能让优化器知道某个表多大呢?这就需要对表收集统计信息。我们在第一章提到的基数、直方图、集群因子等概念都需要事先收集统计信息才能得到。
统计信息类似于战争中的侦察兵,如果情报工作没有做好,打仗就会输掉战争。同样的道理,如果没有正确地收集表的统计信息,或者没有及时地更新表的统计信息,SQL的执行计划就会跑偏,SQL也就会出现性能问题。收集统计信息是为了让优化器选择最佳执行计划,以最少的代价(成本)查询出表中的数据。
统计信息主要分为表的统计信息、列的统计信息、索引的统计信息、系统的统计信息、数据字典的统计信息以及动态性能视图基表的统计信息。
关于系统的统计信息、数据字典的统计信息以及动态性能视图基表的统计信息本书不做讨论,本书重点讨论表的统计信息、列的统计信息以及索引的统计信息。
表的统计信息主要包含表的总行数(num_rows)、表的块数(blocks)以及行平均长度(avg_row_len),我们可以通过查询数据字典DBA_TABLES获取表的统计信息。
现在我们创建一个测试表T_STATS。
SQL> create table t_stats as select * from dba_objects; Table created.
我们查看表T_STATS常用的表的统计信息。
SQL> select owner, table_name, num_rows, blocks, avg_row_len 2 from dba_tables 3 where owner = 'SCOTT' 4 and table_name = 'T_STATS'; OWNER TABLE_NAME NUM_ROWS BLOCKS AVG_ROW_LEN --------------- --------------- ---------- ---------- ----------- SCOTT T_STATS
因为T_STATS是新创建的表,没有收集过统计信息,所以从DBA_TABLES查询数据是空的。
现在我们来收集表T_STATS的统计信息。
SQL> BEGIN 2 DBMS_STATS.GATHER_TABLE_STATS(ownname => 'SCOTT', 3 tabname => 'T_STATS', 4 estimate_percent => 100, 5 method_opt => 'for all columns size auto', 6 no_invalidate => FALSE, 7 degree => 1, 8 cascade => TRUE); 9 END; 10 / PL/SQL procedure successfully completed.
我们再次查看表的统计信息。
SQL> select owner, table_name, num_rows, blocks, avg_row_len 2 from dba_tables 3 where owner = 'SCOTT' 4 and table_name = 'T_STATS'; OWNER TABLE_NAME NUM_ROWS BLOCKS AVG_ROW_LEN --------------- --------------- ---------- ---------- ----------- SCOTT T_STATS 72674 1061 97
从查询中我们可以看到,表T_STATS一共有72 674行数据,1 061个数据块,平均行长度为97字节。
列的统计信息主要包含列的基数、列中的空值数量以及列的数据分布情况(直方图)。我们可以通过数据字典DBA_TAB_COL_STATISTICS查看列的统计信息。
现在我们查看表T_STATS常用的列统计信息。
SQL> select column_name, num_distinct, num_nulls, num_buckets, histogram 2 from dba_tab_col_statistics 3 where owner = 'SCOTT' 4 and table_name = 'T_STATS'; COLUMN_NAME NUM_DISTINCT NUM_NULLS NUM_BUCKETS HISTOGRAM --------------- ------------ ---------- ----------- -------------------- EDITION_NAME 0 72674 0 NONE NAMESPACE 21 1 1 NONE SECONDARY 2 0 1 NONE GENERATED 2 0 1 NONE TEMPORARY 2 0 1 NONE STATUS 2 0 1 NONE TIMESTAMP 1592 1 1 NONE LAST_DDL_TIME 1521 1 1 NONE CREATED 1472 0 1 NONE OBJECT_TYPE 45 0 1 NONE DATA_OBJECT_ID 7796 64833 1 NONE OBJECT_ID 72673 1 1 NONE SUBOBJECT_NAME 140 72145 1 NONE OBJECT_NAME 44333 0 1 NONE OWNER 31 0 1 NONE 15 rows selected.
上面查询中,第一个列表示列名字,第二个列表示列的基数,第三个列表示列中NULL值的数量,第四个列表示直方图的桶数,最后一个列表示直方图类型。
在工作中,我们经常使用下面脚本查看表和列的统计信息。
SQL> select a.column_name, 2 b.num_rows, 3 a.num_nulls, 4 a.num_distinct Cardinality, 5 round(a.num_distinct / b.num_rows * 100, 2) selectivity, 6 a.histogram, 7 a.num_buckets 8 from dba_tab_col_statistics a, dba_tables b 9 where a.owner = b.owner 10 and a.table_name = b.table_name 11 and a.owner = 'SCOTT' 12 and a.table_name = 'T_STATS'; COLUMN_NAME NUM_ROWS NUM_NULLS CARDINALITY SELECTIVITY HISTOGRAM NUM_BUCKETS --------------- ---------- ---------- ----------- ----------- --------------- ------- EDITION_NAME 72674 72674 0 0 NONE 0 NAMESPACE 72674 1 21 .03 NONE 1 SECONDARY 72674 0 2 0 NONE 1 GENERATED 72674 0 2 0 NONE 1 TEMPORARY 72674 0 2 0 NONE 1 STATUS 72674 0 2 0 NONE 1 TIMESTAMP 72674 1 1592 2.19 NONE 1 LAST_DDL_TIME 72674 1 1521 2.09 NONE 1 CREATED 72674 0 1472 2.03 NONE 1 OBJECT_TYPE 72674 0 45 .06 NONE 1 DATA_OBJECT_ID 72674 64833 7796 10.73 NONE 1 OBJECT_ID 72674 1 72673 100 NONE 1 SUBOBJECT_NAME 72674 72145 140 .19 NONE 1 OBJECT_NAME 72674 0 44333 61 NONE 1 OWNER 72674 0 31 .04 NONE 1 15 rows selected.
索引的统计信息主要包含索引blevel(索引高度-1)、叶子块的个数(leaf_blocks)以及集群因子(clustering_factor)。我们可以通过数据字典DBA_INDEXES查看索引的统计信息。
我们在OBJECT_ID列上创建一个索引。
SQL> create index idx_t_stats_id on t_stats(object_id); Index created.
创建索引的时候会自动收集索引的统计信息,运行下面脚本查看索引的统计信息。
SQL> select blevel, leaf_blocks, clustering_factor,status 2 from dba_indexes 3 where owner = 'SCOTT' 4 and index_name = 'IDX_T_STATS_ID'; BLEVEL LEAF_BLOCKS CLUSTERING_FACTOR STATUS ---------- ----------- ----------------- ---------------- 1 161 1127 VALID
如果要单独对索引收集统计信息,可以使用下面脚本收集。
SQL> BEGIN 2 DBMS_STATS.GATHER_INDEX_STATS(ownname => 'SCOTT', 3 indname => 'IDX_T_STATS_ID'); 4 END; 5 / PL/SQL procedure successfully completed.
在本书第6章中,我们会详细介绍表的统计信息、列的统计信息以及索引的统计信息是如何被应用于成本计算的。