选择性(Selectivity)
概念
选择性定义:
选择性是指某列的基数与总行数的比值,再乘以100%。公式如下: 选择性=( 总行数/ 基数 )×100%
选择性用于衡量一个列在查询中的区分能力。高选择性意味着一个列能在很大程度上过滤数据,低选择性则表示数据分布比较均匀,可能需要更多的扫描。
应用场景:
在SQL优化时,单独看列的基数没有意义,必须将基数与总行数对比才有实际意义。因此,引入选择性这一概念来帮助优化查询性能。
收集统计信息
收集统计信息:
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(
ownname => 'SCOTT',
tabname => 'TEST',
estimate_percent => 100,
method_opt => 'for all columns size 1',
no_invalidate => FALSE,
degree => 1,
cascade => TRUE
);
END;
/上述过程收集了 SCOTT
用户下的TEST
表的完整统计信息。这包括每列的基数、选择性等。为了查看选择性,必须先收集表的统计信息。在Oracle数据库中,可以通过 DBMS_STATS.GATHER_TABLE_STATS
过程来完成。实际操作:
收集统计信息非常重要,它影响查询优化器的决策,确保执行计划的效率和准确性。
检查列的基数与选择性
查询各列基数与选择性:
SELECT a.column_name,
b.num_rows,
a.num_distinct Cardinality,
ROUND(a.num_distinct / b.num_rows * 100, 2) selectivity,
a.histogram,
a.num_buckets
FROM dba_tab_col_statistics a, dba_tables b
WHERE a.owner = b.owner
AND a.table_name = b.table_name
AND a.owner = 'SCOTT'
AND a.table_name = 'TEST';这段SQL脚本用于查询 TEST
表中各列的基数和选择性。结果展示了列名、行数、基数、选择性、直方图信息和桶数(Buckets)。结果分析:
OBJECT_ID
列的选择性为100%,表明每个值都是唯一的,非常适合用于索引。OWNER
列的选择性为0.04%,说明数据分布不均匀,大部分数据可能集中在少数值中。
数据分布与选择性应用
分析数据分布:
SELECT *
FROM (SELECT object_name, COUNT(*)
FROM test
GROUP BY object_name
ORDER BY 2 DESC)
WHERE ROWNUM <= 10;这段查询用于查看 object_name
列的数据分布,输出前10行数据的分布情况。示例结果:
OBJECT_NAME
列的数据选择性为61.05%,分布相对均衡,适合使用索引。但也需注意 DBMS_REPCAT_AUTH
的计数仅为5,显示有些数据分布不均匀,选择性策略需要结合实际情况调整。
列在查询中的作用
查看列的查询参与情况:
BEGIN
DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO;
END;
/通过刷新数据库监控信息,确保最新的统计数据反映在优化决策中。 查看WHERE条件中出现的列:
SELECT r.name owner,
o.name table_name,
c.name column_name,
equality_preds,
equijoin_preds,
nonequijoin_preds,
range_preds,
like_preds,
null_preds,
timestamp
FROM sys.col_usage$ u,
sys.obj$ o,
sys.col$ c,
sys.user$ r
WHERE o.obj# = u.obj#
AND c.obj# = u.obj#
AND c.col# = u.intcol#
AND r.name = 'SCOTT'
AND o.name = 'TEST';此查询显示了哪些列出现在WHERE子句中,及其参与的过滤条件类型(等值、范围、LIKE等)。 实际应用:
确定某列是否常用作查询条件,可以帮助决定是否为其创建索引。
执行一个示例查询
执行选择性分析:
SELECT object_id, owner, object_type
FROM test
WHERE owner = 'SYS'
AND object_id < 100
AND ROWNUM <= 10;此查询用于快速获取 owner
为SYS
且object_id
小于100的前10个对象,结合选择性信息判断查询效率。
详细举例
例子1:高选择性列的索引应用
有一个客户表(customers)
,其中的email
字段是唯一的,选择性为100%。
-- 为高选择性字段创建索引
CREATE INDEX idx_customers_email ON customers(email);
-- 执行查询
SELECT * FROM customers WHERE email = 'example@example.com';
分析:
由于 email
字段具有高选择性,为其创建索引能够大大提升查询效率,尤其是在执行等值查询时。
例子2:低选择性列的索引决策
在订单表(orders)
中,status
字段表示订单状态,可能有以下几种状态:'Pending'
, 'Shipped'
, 'Delivered'
。假设选择性仅为5%。
-- 不建议为低选择性字段创建索引
SELECT * FROM orders WHERE status = 'Pending';
分析:
由于 status
字段选择性较低,不适合使用索引,因为数据分布不均匀,索引效率不高,全表扫描可能更合适。
例子3:结合选择性和基数优化查询
在一个产品表(products)
中,分析category_id
字段的选择性和基数以优化查询。
-- 查询选择性
SELECT category_id, COUNT(*)
FROM products
GROUP BY category_id
ORDER BY COUNT(*) DESC;
-- 判断是否创建索引
-- 如果某个category_id的选择性超过20%,考虑创建索引
CREATE INDEX idx_products_category ON products(category_id);
分析:
当某个 category_id
的选择性显著高于其他值(大于20%),创建索引能提高针对特定类别的查询效率。
非常感谢您读到这里!如果您觉得这篇文章对您有帮助,可以关注一下博主。关注后,您将第一时间获得最新的AI、云计算、运维(Linux、数据库,容器等)技术,以及更多实用的技能干货。
让AI工具成为你的得力助手,感受AI工具的无限可能,让复杂的任务变得简单,让你的工作更加轻松和高效。

文章转载自周同学带您玩AI,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




