SQL优化核心思想
上QQ阅读APP看书,第一时间看更新

第1章 SQL优化必懂概念

某个列唯一键(Distinct_Keys)的数量叫作基数。比如性别列,该列只有男女之分,所以这一列基数是2。主键列的基数等于表的总行数。基数的高低影响列的数据分布。

以测试表test为例,owner列和object_id列的基数分别如下所示。

SQL> select count(distinct owner),count(distinct object_id),count(*) from test;

COUNT(DISTINCTOWNER) COUNT(DISTINCTOBJECT_ID)   COUNT(*)
-------------------- ------------------------ ----------
                  29                    72462      72462

TEST表的总行数为72 462,owner列的基数为29,说明owner列里面有大量重复值,object_id列的基数等于总行数,说明object_id列没有重复值,相当于主键。owner列的数据分布如下。

SQL> select owner,count(*) from test group by owner order by 2 desc;

OWNER                  COUNT(*)
-------------------- ----------
SYS                       30808
PUBLIC                    27699
SYSMAN                     3491
ORDSYS                     2532
APEX_030200                2406
MDSYS                      1509
XDB                         844
OLAPSYS                     719
SYSTEM                      529
CTXSYS                      366
WMSYS                       316
EXFSYS                      310
SH                          306
ORDDATA                     248
OE                          127
DBSNMP                       57
IX                           55
HR                           34
PM                           27
FLOWS_FILES                  12
OWBSYS_AUDIT                 12
ORDPLUGINS                   10
OUTLN                         9
BI                            8
SI_INFORMTN_SCHEMA            8
ORACLE_OCM                    8
SCOTT                         7
APPQOSSYS                     3
OWBSYS                        2

owner列的数据分布极不均衡,我们运行如下SQL。

select * from test where owner='SYS';

SYS有30 808条数据,从72 462条数据里面查询30 808条数据,也就是说要返回表中42.5%的数据。

SQL> select 30808/72462*100 "Percent" from dual;

   Percent
----------
42.5160774

那么请思考,你认为以上查询应该使用索引吗?现在我们换一种查询语句。

select * from test where owner='SCOTT';

SCOTT有7条数据,从72 462条数据里面查询7条数据,也就是说要返回表中0.009%的数据。

SQL> select 7/72462*100 "Percent" from dual;

   Percent
----------
.009660236

请思考,返回表中0.009%的数据应不应该走索引?

如果你还不懂索引,没关系,后面的章节我们会详细介绍。如果你回答不了上面的问题,我们先提醒一下。当查询结果是返回表中5%以内的数据时,应该走索引;当查询结果返回的是超过表中5%的数据时,应该走全表扫描。

当然了,返回表中5%以内的数据走索引,返回超过5%的数据就使用全表扫描,这个结论太绝对了,因为你还没掌握后面章节的知识,这里暂且记住5%这个界限就行。我们之所以在这里讲5%,是怕一些初学者不知道上面问题的答案而纠结。

现在有如下查询语句。

select * from test where owner=:B1;

语句中,“:B1”是绑定变量,可以传入任意值,该查询可能走索引也可能走全表扫描。

现在得到一个结论:如果某个列基数很低,该列数据分布就会非常不均衡,由于该列数据分布不均衡,会导致SQL查询可能走索引,也可能走全表扫描。在做SQL优化的时候,如果怀疑列数据分布不均衡,我们可以使用select列,count(*) from表group by列order by 2 desc来查看列的数据分布。

如果SQL语句是单表访问,那么可能走索引,可能走全表扫描,也可能走物化视图扫描。在不考虑有物化视图的情况下,单表访问要么走索引,要么走全表扫描。现在,回忆一下走索引的条件:返回表中5%以内的数据走索引,超过5%的时候走全表扫描。相信大家读到这里,已经搞懂了单表访问的优化方法。

我们来看如下查询。

select * from test where object_id=:B1;

不管object_id传入任何值,都应该走索引。

我们再思考如下查询语句。

select * from test where object_name=:B1;

不管给object_name传入任何值,请问该查询应该走索引吗?

请你去查看object_name的数据分布。写到这里,其实有点想把本节名称改为“数据分布”。大家在以后的工作中一定要注意列的数据分布!