这篇文章主要介绍“Oracle 12C中的Statistics on Column Groups分析”,在日常操作中,相信很多人在Oracle 12C中的Statistics on Column Groups分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Oracle 12C中的Statistics on Column Groups分析”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

Statistics on Column Groups
单个列统计信息对于判断where子句中的单个谓词的选择性是非常有用的。然而,当where子句中包含来自相同表的不同列的多个谓词时,单个列统计信息不能显示列之间的关系。使用列组(column group)就是用来解决这个问题的。优化器单独计算谓词的选择性,然后合并它们。然而,如果在单列之间存在关联,那么优化器当评估基数时不会考虑它,优化器会使用每个表谓词的选择性来乘以行数来评估基数。

下面的语句查询dba_tab_col_statistics表来显示关于sh.customers表中列cust_state_province与country_id列的统计信息。

SQL>COLCOLUMN_NAMEFORMATa20SQL>COLNDVFORMAT999SQL>SELECTCOLUMN_NAME,NUM_DISTINCTAS"NDV",HISTOGRAM2FROMDBA_TAB_COL_STATISTICS3WHEREOWNER='SH'4ANDTABLE_NAME='CUSTOMERS'5ANDCOLUMN_NAMEIN('CUST_STATE_PROVINCE','COUNTRY_ID');COLUMN_NAMENDVHISTOGRAM---------------------------------------CUST_STATE_PROVINCE145FREQUENCYCOUNTRY_ID19FREQUENCY

下面的语句查询住在California的客户人数3341人:

SQL>SELECTCOUNT(*)2FROMsh.customers3WHEREcust_state_province='CA';COUNT(*)----------3341

来显示查询state为CA,country_id为52790(USA)的客户人数的查询执行

SQL>EXPLAINPLANFOR2SELECT*3FROMsh.customers4WHEREcust_state_province='CA'5ANDcountry_id=52790;Explained.SQL>SELECT*FROMTABLE(DBMS_XPLAN.DISPLAY);PLAN_TABLE_OUTPUT--------------------------------------------------------------------------------Planhashvalue:2008213504-------------------------------------------------------------------------------|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|-------------------------------------------------------------------------------|0|SELECTSTATEMENT||1115|205K|423(1)|00:00:01||*1|TABLEACCESSFULL|CUSTOMERS|1115|205K|423(1)|00:00:01|-------------------------------------------------------------------------------PredicateInformation(identifiedbyoperationid):---------------------------------------------------PLAN_TABLE_OUTPUT--------------------------------------------------------------------------------1-filter("CUST_STATE_PROVINCE"='CA'AND"COUNTRY_ID"=52790)Note------automaticDOP:ComputedDegreeofParallelismis1becauseofparallelthreshold17rowsselected.

基于单列country_id和cust_state_province列的统计信息,优化器评估住在USA的California的客户人数是1115,而实际上有3341人,但优化器不知道,所以通过所有谓词减少了返回的行数因此大大降低了评估基数。可以通过收集列组统计信息来让优化器知晓列country_id与cust_state_province之间的真实关系。

自动与手动列组统计信息
Oracle数据库可以自动或手动创建列组统计信息。优化器可以使用SQL执行计划指令来生成更优的执行计划。如果dbms_stats引用参数auto_stat_extensions被设置为ON(缺省值为OFF),那么SQL执行计划指令基于工作量中谓词的使用情况可以自动触发来创建列组统计信息。可以通过set_table_prefs,set_global_prefs或set_schema_prefs过程来设置auto_stat_extensions。

当想要手动管理列组统计信息时,可以使用dbms_stats来执行以下操作:
.探测列组
.创建以前探测到的列组
.手动创建列组并收集列组统计信息

列组统计信息用户接口
有几个dbms_stats程序单元有与列组相关的引用参数
seed_col_usage过程,迭代指定工作量中的SQL语句,编译它们,然后查看在这些语句谓词中出现列的使用信息。为了决定合适的列组,数据库必须观察一个有代表性的工作量。在监控期间不需要运行查询本身。可以对在工作量中那些运行时间长的查询执行explain plan来确保数据库记录这些查询所使用的列组信息。

report_col_usage函数,生成一个报告列出在工作量中所看到的过滤谓词,连接谓词与group by子句中的列。可以使用这个函数来检查对于指定表所记录的列使用信息。

create_extended_stats函数,创建扩展,它可以是列组或表达式。当用户手动或自动统计信息收集任务对表收集统计信息时数据库会对扩展收集统计信息。

auto_stat_extensions引用参数,控制自动创建扩展,包括列组,当优化器统计信息被收集时,使用set_table_prefs,set_schema_prefs或set_global_prefs来设置这个引用参数。当auto_stat_extensions被设置为off(缺省值)时,数据库不会自动创建列组统计信息。为了创建扩展,你必须执行create_extended_stats函数或在dbms_stats API中的method_opt参数中显性指定扩展统计信息。当auto_stat_extensions设置为ON时,一个SQL执行计划指令基于工作量中谓词中列的使用信息可以触发自动创建列组统计信息。

为特定的工作量检测有用的列组
可以使用dbms_stats.seed_col_usage与report_col_usage来基于特定工作量来决定那个表需要列组。当你不知道需要创建什么样的扩展统计信息时这种技术很有用。这种技术对于扩展统计信息不会工作。

假设存在以下情况:
.查询sh.customers_test表(用customers表来创建)并在谓词中使用了country_id与cust_state_province列但基数评估不正确。

.想要数据库监控工作量5分钟(300秒)。

.想要数据库自动判断需要那些列组。

为了检测列组需要执行以下操作:
1.启动SQL*Plus或SQL Developer,并以用户sh登录数据库

2.创建表customers_test并收集统计信息:

SQL>DROPTABLEcustomers_test;Tabledropped.SQL>CREATETABLEcustomers_testASSELECT*FROMcustomers;Tablecreated.SQL>EXECDBMS_STATS.GATHER_TABLE_STATS(user,'customers_test');PL/SQLproceduresuccessfullycompleted.

3.启用工作量监控
在不同的SQL*Plus会话中,以sys用户登录并执行以下的PL/SQL程序来启用监控300秒:

SQL>BEGIN2DBMS_STATS.SEED_COL_USAGE(null,null,300);3END;4/PL/SQLproceduresuccessfullycompleted.

4.以用户sh来在使用工作量的情况下对两个查询解析它们的执行计划。

SQL>EXPLAINPLANFOR2SELECT*3FROMcustomers_test4WHEREcust_city='LosAngeles'5ANDcust_state_province='CA'6ANDcountry_id=52790;Explained.SQL>SELECTPLAN_TABLE_OUTPUT2FROMTABLE(DBMS_XPLAN.DISPLAY('plan_table',null,'basicrows'));Planhashvalue:2112738156----------------------------------------------------|Id|Operation|Name|Rows|----------------------------------------------------|0|SELECTSTATEMENT||1||1|TABLEACCESSFULL|CUSTOMERS_TEST|1|----------------------------------------------------8rowsselected.SQL>EXPLAINPLANFOR2SELECTcountry_id,cust_state_province,count(cust_city)3FROMcustomers_test4GROUPBYcountry_id,cust_state_province;Explained.SQL>SELECTPLAN_TABLE_OUTPUT2FROMTABLE(DBMS_XPLAN.DISPLAY('plan_table',null,'basicrows'));Planhashvalue:1820398555-----------------------------------------------------|Id|Operation|Name|Rows|-----------------------------------------------------|0|SELECTSTATEMENT||1949||1|HASHGROUPBY||1949||2|TABLEACCESSFULL|CUSTOMERS_TEST|55500|-----------------------------------------------------9rowsselected.

第一个执行计划显示基数为1而查询返回932行记录,第二个执行计划显示基数为1949而查询返回145行记录。

5.可选操作,检查对表customers_test所记录的列使用信息

SQL>SETLONG100000SQL>SETLINES120SQL>SETPAGES0SQL>SELECTDBMS_STATS.REPORT_COL_USAGE(user,'customers_test')2FROMDUAL;LEGEND:.......EQ:UsedinsingletableEQualitypredicateRANGE:UsedinsingletableRANGEpredicateLIKE:UsedinsingletableLIKEpredicateNULL:Usedinsingletableis(not)NULLpredicateEQ_JOIN:UsedinEQualityJOINpredicateNONEQ_JOIN:UsedinNONEQualityJOINpredicateFILTER:UsedinsingletableFILTERpredicateJOIN:UsedinJOINpredicateGROUP_BY:UsedinGROUPBYexpression...............................................................................###############################################################################COLUMNUSAGEREPORTFORSH.CUSTOMERS_TEST.........................................1.COUNTRY_ID:EQ2.CUST_CITY:EQ3.CUST_STATE_PROVINCE:EQ4.(CUST_CITY,CUST_STATE_PROVINCE,COUNTRY_ID):FILTER5.(CUST_STATE_PROVINCE,COUNTRY_ID):GROUP_BY###############################################################################

在上面的报告中,前三个列是第一个监控查询中等值谓词中所使用的三个列:

...WHEREcust_city='LosAngeles'ANDcust_state_province='CA'ANDcountry_id=52790;

所有三个列出现在相同的where子句中,因此报告显示他们作为一组。在第二个查询中,两个列出现在group by子句中,因此报告标记它们作为group_by。在filter与group_by中的列组就是列组的候选者。

在工作量监控下创建所检测到的列组
可以使用dbms_stats.create_extended_stats函数来为执行dbms_stats.seed_col_usage所检测到的列组来创建列组,具体操作如下:
1.基于在监控窗口期间所捕获到的列使用信息来为customers_test表创建列组,执行下面的查询

SQL>SELECTDBMS_STATS.CREATE_EXTENDED_STATS(user,'customers_test')FROMDUAL;###############################################################################EXTENSIONSFORSH.CUSTOMERS_TEST................................1.(CUST_CITY,CUST_STATE_PROVINCE,COUNTRY_ID):SYS_STUMZ$C3AIHLPBROI#SKA58H_Ncreated2.(CUST_STATE_PROVINCE,COUNTRY_ID):SYS_STU#S#WF25Z#QAHIHE#MOFFMM_created###############################################################################

数据库将为customers_test表创建两个列组:一个列组是过滤谓词,一个列组是group by操作。

2.重新收集表统计信息

SQL>EXECDBMS_STATS.GATHER_TABLE_STATS(user,'customers_test');PL/SQLproceduresuccessfullycompleted.

3.以用户sh来查询user_tab_col_statistics视图来判断数据库创建了那些额外统计信息:

SQL>SELECTCOLUMN_NAME,NUM_DISTINCT,HISTOGRAM2FROMUSER_TAB_COL_STATISTICS3WHERETABLE_NAME='CUSTOMERS_TEST'4ORDERBY1;COUNTRY_ID19FREQUENCYCUST_CITY620HYBRIDCUST_CITY_ID620NONECUST_CREDIT_LIMIT8NONECUST_EFF_FROM1NONECUST_EFF_TO0NONECUST_EMAIL1699NONECUST_FIRST_NAME1300NONECUST_GENDER2NONECUST_ID55500NONECUST_INCOME_LEVEL12NONECUST_LAST_NAME908NONECUST_MAIN_PHONE_NUMBER51344NONECUST_MARITAL_STATUS11NONECUST_POSTAL_CODE623NONECUST_SRC_ID0NONECUST_STATE_PROVINCE145FREQUENCYCUST_STATE_PROVINCE_ID145NONECUST_STREET_ADDRESS49900NONECUST_TOTAL1NONECUST_TOTAL_ID1NONECUST_VALID2NONECUST_YEAR_OF_BIRTH75NONESYS_STU#S#WF25Z#QAHIHE#MOFFMM_145NONESYS_STUMZ$C3AIHLPBROI#SKA58H_N620HYBRID25rowsselected.

上面的查询显示了由dbms_stats.create_extended_stats函数所返回的两个列组名。为CUST_CITY, CUST_STATE_PROVINCE和COUNTRY_ID列所创建的列组有一个HYBRID类型的直方图统计信息。

4.再次解析之前的两个查询语句的执行计划

SQL>EXPLAINPLANFOR2SELECT*3FROMcustomers_test4WHEREcust_city='LosAngeles'5ANDcust_state_province='CA'6ANDcountry_id=52790;Explained.SQL>SELECTPLAN_TABLE_OUTPUT2FROMTABLE(DBMS_XPLAN.DISPLAY('plan_table',null,'basicrows'));Planhashvalue:2112738156----------------------------------------------------|Id|Operation|Name|Rows|----------------------------------------------------|0|SELECTSTATEMENT||874||1|TABLEACCESSFULL|CUSTOMERS_TEST|874|----------------------------------------------------8rowsselected.SQL>EXPLAINPLANFOR2SELECTcountry_id,cust_state_province,count(cust_city)3FROMcustomers_test4GROUPBYcountry_id,cust_state_province;Explained.SQL>SELECTPLAN_TABLE_OUTPUT2FROMTABLE(DBMS_XPLAN.DISPLAY('plan_table',null,'basicrows'));Planhashvalue:1820398555-----------------------------------------------------|Id|Operation|Name|Rows|-----------------------------------------------------|0|SELECTSTATEMENT||145||1|HASHGROUPBY||145||2|TABLEACCESSFULL|CUSTOMERS_TEST|55500|-----------------------------------------------------9rowsselected.

第一个查询评估的基数是874,要返回的记录数是932,第二个查询评估的基数是145,要返回的记录数是145,这样基数评估的记录数与实际返回的记录已经非常接近了,这就是列组统计信息所带来的好处。

手动创建与收集列组统计信息
在有些情况下,可能知道想要创建的列组。dbms_stats.gather_table_stats函数的method_opt参数可以自动创建与收集列组统计信息。可以通过使用for columns来指定列组从而来创建一个新的列组。

假设存在以下情况:
.想要对sh.customers表上的cust_state_province与country_id列创建列组。

.想要对sh.customers表与新的列组收集统计信息。

手动创建与收集列组统计信息执行以下操作:
1.启动SQL*Plus并以sh用户登录数据库。

2.使用以下PL/SQL程序来创建列组并收集统计信息:

SQL>BEGIN2DBMS_STATS.GATHER_TABLE_STATS('sh','customers',3METHOD_OPT=>'FORALLCOLUMNSSIZESKEWONLY'||4'FORCOLUMNSSIZESKEWONLY(cust_state_province,country_id)');5END;6/PL/SQLproceduresuccessfullycompleted.

显示列组信息
为了获得列组名,可以使用dbms_stats.show_extended_stats_name函数或数据库视图。也可以使用视图来获得信息比如,distinct值的数量与列组是否有直方图统计信息。
1.启动SQL*Plus并以sh用户登录数据库。

2.为了获得列组名,执行以下PL/SQL程序

SQL>SELECTSYS.DBMS_STATS.SHOW_EXTENDED_STATS_NAME('sh','customers',2'(cust_state_province,country_id)')col_group_name3FROMDUAL;COL_GROUP_NAME------------------------------------SYS_STU#S#WF25Z#QAHIHE#MOFFMM_

查询user_stat_extensions视图

SQL>SELECTEXTENSION_NAME,EXTENSION2FROMUSER_STAT_EXTENSIONS3WHERETABLE_NAME='CUSTOMERS';EXTENSION_NAMEEXTENSION-----------------------------------------------------------------------------------------------------------SYS_STU#S#WF25Z#QAHIHE#MOFFMM_("CUST_STATE_PROVINCE","COUNTRY_ID")

3.查询创建的列组的distinct值的数量并查看是否创建了直方图

SQL>SELECTe.EXTENSIONcol_group,t.NUM_DISTINCT,t.HISTOGRAM2FROMUSER_STAT_EXTENSIONSe,USER_TAB_COL_STATISTICSt3WHEREe.EXTENSION_NAME=t.COLUMN_NAME4ANDe.TABLE_NAME=t.TABLE_NAME5ANDt.TABLE_NAME='CUSTOMERS';COL_GROUPNUM_DISTINCTHISTOGRAM-------------------------------------------------------------------------------------------("CUST_STATE_PROVINCE","COUNTRY_ID")145FREQUENCY

删除列组
可以使用dbms_stats.drop_extended_stats函数来从表中删除列组

SQL>BEGIN2DBMS_STATS.DROP_EXTENDED_STATS('sh','customers',3'(cust_state_province,country_id)');4END;5/PL/SQLproceduresuccessfullycompleted.

到此,关于“Oracle 12C中的Statistics on Column Groups分析”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!