对于Oracle优化的课题中,基数和选择性是两个重要的概念。那么什么是基数和选择性呢。
基数:某一列,不同唯一键的数量。
比如,有一个一万行的表,它的sex列只有男和女这两个值,那么,这列的基数便是2了。所以,主键列的基数等于表的行数。
选择性=基数/行数
像上面所说的表,它的选择性便是2/10000=0.0002了。
以上便是基数和选择性的基本概念了,那么它们一般是用来干什么的呢。
基数和选择性有时候也是被当作是否建立索引的判断之一,对一个列来说,基数和选择性越高的列便越适合建立Btree索引。但是当基数和选择性都十分地低的时候,这时候就需要看数据分布的情况来决定是否适合建立Btree 索引。比如:
一个表中,id列往往是不会重复的值,在这个列上建立Btree索引,往往是高效的。但是像是在性别列上,只会有男或者女这两个值,基数和选择性都比较低。这时要看数据的分布情况,若是男女数量各占一半,那么这列就不需要建立Btree 索引,走全表扫描甚至比走Btree 索引 快。若是比较特殊的,像是理工类大学,男女比例可能达到10:1,这时就可以创建索引,因为在查询条件为where sex='女'时,可以让它走Btree 索引,在where sex='男'时,走全表扫描即可。这样当查询女生的时候,效率往往就快很多了。
如何查看某个列的基数和选择性,以下有两个脚本。
第一个,取得实际的基数和选择性
select count(distinct column_name),count(*) total_rows,count(distinct column_name) / count(*) * 100 selectivity from table_name;
但是,若是segment_size过大(甚至超过SGA的buffer_cache),那么仔细考虑了,它会挤掉buffer_cache中很多数据,甚至很多热块。可能会对生产环境产生严重的影响。
第二个,通过统计信息表查看
select a.column_name,
b.num_rows,
a.num_distinct Cardinality,
round(a.num_distinct / b.num_rows * 100, 2) selectivity,
from dba_tab_col_statistics a, dba_tables b
where a.owner = b.owner
and a.table_name = b.table_name
and a.owner = upper('&owner')
and a.table_name = upper('&table_name')
and a.column_name = upper('&column_name');
这个脚本严重依赖表的统计信息,若是统计信息有严重的错误,那么该脚本返回的数据也可能是不准确的。
生产环境中一般推荐第二种,若是表的segment_size不大,使用第一种也可。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/31386161/viewspace-2132419/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/31386161/viewspace-2132419/