知识大全 解析一个通过添加本地分区索引提高SQL性能的案例
Posted 索引
篇首语:敢说敢作敢为, 无怨无恨无悔。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 解析一个通过添加本地分区索引提高SQL性能的案例相关的知识,希望对你有一定的参考价值。
解析一个通过添加本地分区索引提高SQL性能的案例 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
今天接到同事求助 说有一个select query 在Oracle上要跑一分多钟 他希望能在 s内出结果 以下就是解决这个问题的方法 需要的朋友可以参考下该sql如下
复制代码 代码如下: Select /*+ parallel(src ) */ distinct src systemname as systemname src databasename as databasename src tablename as tablename src username as username from <STRONG>meta_dbql_table_usage_exp_hst</STRONG> src inner <STRONG>join DR_QRY_LOG_EXP_HST</STRONG> rl on <STRONG>src acctstringdate = rl acctstringdate and src queryid = rl queryid</STRONG> And Src Systemname = Rl Systemname and src acctstringdate > sysdate And Rl Acctstringdate > Sysdate inner join <STRONG>meta_dr_qry_log_tgt_all_hst </STRONG>tgt on upper(tgt systemname) = upper( MOZART ) And Upper(tgt Databasename) = Upper( GDW_TABLES ) And Upper(tgt Tablename) = Upper( SSA_SLNG_LSTG_MTRC_SD ) <STRONG>AND src acctstringdate = tgt acctstringdate and rl statement_id = tgt statement_id</STRONG> and rl systemname = tgt systemname And Tgt Acctstringdate > Sysdate And Not( Upper(Tgt Systemname)=Upper(src systemname) And Upper(Tgt Databasename) = Upper(Src Databasename) And Upper(Tgt Tablename) = Upper(Src Tablename) ) And tgt Systemname is not null And tgt Databasename Is Not Null And tgt tablename is not nullSQL的简单分析 总 得来看 这个SQL就是三个表 (meta_dbql_table_usage_exp_hst DR_QRY_LOG_EXP_HST meta_dr_qry_log_tgt_all_hst) 的INNER JOIN 这三个表数据量都在百万级别 且都是分区表(以acctstringdate为分区键) 执行计划如下
复制代码 代码如下: | Id | Operation | Name | Rows | Bytes | Cost | Pstart| Pstop | | | SELECT STATEMENT | | | | | | | | | PX COORDINATOR | | | | | | | | | PX SEND QC (RANDOM) | :TQ | | | | | | | | SORT UNIQUE | | | | | | | | | PX RECEIVE | | | | | | | | | PX SEND HASH | :TQ | | | | | | |* | TABLE ACCESS BY LOCAL INDEX ROWID| DR_QRY_LOG_EXP_HST | | | | | | | | NESTED LOOPS | | | | | | | | | NESTED LOOPS | | | K| | | | | | BUFFER SORT | | | | | | | | | PX RECEIVE | | | | | | | | | PX SEND BROADCAST | :TQ | | | | | | | | PARTITION RANGE ITERATOR | | | | | KEY | | |* | TABLE ACCESS FULL | META_DR_QRY_LOG_TGT_ALL_HST | | | | KEY | | | | PX BLOCK ITERATOR | | | K| | KEY | KEY | |* | TABLE ACCESS FULL | META_DBQL_TABLE_USAGE_EXP_HST | | K| | KEY | KEY | | | PARTITION RANGE ITERATOR | | | | | KEY | KEY | |* | INDEX RANGE SCAN | DR_QRY_LOG_EXP_HST_IDX | | | | KEY | KEY | Predicate Information (identified by operation id): filter("RL" "STATEMENT_ID"="TGT" "STATEMENT_ID" AND "RL" "SYSTEMNAME"="TGT" "SYSTEMNAME" AND "SRC" "SYSTEMNAME"="RL" "SYSTEMNAME") filter(UPPER("TGT" "SYSTEMNAME")= MOZART AND UPPER("TGT" "DATABASENAME")= GDW_TABLES AND UPPER("TGT" "TABLENAME")= SSA_SLNG_LSTG_MTRC_SD AND "TGT" "ACCTSTRINGDATE">SYSDATE@! AND "TGT" "SYSTEMNAME" IS NOT NULL "TGT" "DATABASENAME" IS NOT NULL AND "TGT" "TABLENAME" IS NOT NULL) filter("SRC" "ACCTSTRINGDATE"="TGT" "ACCTSTRINGDATE" AND (UPPER("TGT" "SYSTEMNAME")<>UPPER("SRC" "SYSTEMNAME") OR UPPER("TGT" "DATABASENAME")<>UPPER("SRC" "DATABASENAME") OR UPPER("TGT" "TABLENAME")<>UPPER("SRC" "TABLENAME")) AND "SRC" "ACCTSTRINGDATE">SYSDATE@! ) access("SRC" "QUERYID"="RL" "QUERYID" AND "SRC" "ACCTSTRINGDATE"="RL" "ACCTSTRINGDATE") filter("RL" "ACCTSTRINGDATE">SYSDATE@! )定位问题 从 上面执行计划中的表连接方式可以知道 这三个表之间进行了两次NESTED LOOP 问题出现在最里层的NESTED LOOP(对两个表都做了TABLE FULL SCAN) 因为表都是百万级别的(即时过滤后的数据量也不小) 性能问题就出现在内表(即被驱动 表)META_DBQL_TABLE_USAGE_EXP_HST做了太多次的全表扫描 如果能把全表扫描转换成索引 则性能可以大幅度提高
下面是NESTED LOOP的介绍 嵌套连接把要处理的数据集分为外部循环(驱动数据源)和内部循环(被驱动数据源) 外部循环只执行一次 内部循环执行的次数等于外部循环执行返回的数据个数 这种连接的好处是内存使用非常少 如果驱动数据源有限 且被驱动表在连接列上有相应的索引 则这种连接方式才是高效的 下面是这三个表上索引的情况
复制代码 代码如下: SQL> select index_name table_name from user_indexes where table_name in ( DR_QRY_LOG_EXP_HST upper( meta_dbql_table_usage_exp_hst ) upper( meta_dr_qry_log_tgt_all_hs INDEX_NAME TABLE_NAME META_DR_QRY_LOG_TGT_ALL_IDX META_DR_QRY_LOG_TGT_ALL_HST META_DBQL_TUSAGE_EHST_IDX META_DBQL_TABLE_USAGE_EXP_HST DR_QRY_LOG_EXP_HST_IDX DR_QRY_LOG_EXP_HST CREATE INDEX "GV" "META_DR_QRY_LOG_TGT_ALL_IDX" ON "GV" "META_DR_QRY_LOG_TGT_ALL_HST" ("STATEMENT_ID" "ACCTSTRINGDATE") CREATE INDEX "GV" "META_DBQL_TUSAGE_EHST_IDX" ON "GV" "META_DBQL_TABLE_USAGE_EXP_HST" ("QUERYID" "ACCTSTRINGDATE") CREATE INDEX "GV" "DR_QRY_LOG_EXP_HST_IDX" ON "GV" "DR_QRY_LOG_EXP_HST" ("QUERYID" "ACCTSTRINGDATE")这 三个索引都是本地分区索引(都包含分区键acctstringdate) 很显然 DR_QRY_LOG_EXP_HST表少了个索引 因为它与表 meta_dr_qry_log_tgt_all_hst 在statement_id上做join 因此应该在它的statement_id上也创建本地分区索引如下
复制代码 代码如下: create index DR_QRY_LOG_EXP_HST_IDX on gv DR_QRY_LOG_EXP_HST (statement_id ACCTSTRINGDATE) local;性能对比 新的执行计划如下
复制代码 代码如下: | Id | Operation | Name | Rows | Bytes | Cost | Pstart| Pstop | | | SELECT STATEMENT | | | | | | | | | SORT UNIQUE | | | | | | | |* | TABLE ACCESS BY LOCAL INDEX ROWID | META_DBQL_TABLE_USAGE_EXP_HST | | | | | | | | NESTED LOOPS | | | | | | | | | NESTED LOOPS | | | | | | | | | PARTITION RANGE ITERATOR | | | | | KEY | | |* | TABLE ACCESS FULL | META_DR_QRY_LOG_TGT_ALL_HST | | | | KEY | | | | PARTITION RANGE ITERATOR | | | | | KEY | | |* | TABLE ACCESS BY LOCAL INDEX ROWID| DR_QRY_LOG_EXP_HST | | | | KEY | | |* | <STRONG>INDEX RANGE SCAN | DR_QRY_LOG_EXP_HST_IDX </STRONG> | | | | KEY | | | | PARTITION RANGE ITERATOR | | | | | KEY | KEY | |* | INDEX RANGE SCAN | META_DBQL_TUSAGE_EHST_IDX | | | | KEY | KEY | Predicate Information (identified by operation id): filter((UPPER("TGT" "SYSTEMNAME")<>UPPER("SRC" "SYSTEMNAME") OR UPPER("TGT" "DATABASENAME")<>UPPER("SRC" "DATABASENAME") OR UPPER("TGT" "TABLENAME")<>UPPER("SRC" "TABLENAME")) AND "SRC" "SYSTEMNAME"="RL" "SYSTEMNAME") filter(UPPER("TGT" "SYSTEMNAME")= MOZART AND UPPER("TGT" "DATABASENAME")= GDW_TABLES AND UPPER("TGT" "TABLENAME")= SSA_SLNG_LSTG_MTRC_SD AND "TGT" "ACCTSTRINGDATE">SYSDATE@! AND "TGT" "SYSTEMNAME" IS NOT NULL AND "TGT" "DATABASENAME" IS NOT NULL AND "TGT" "TABLENAME" IS NOT NULL) filter("RL" "SYSTEMNAME"="TGT" "SYSTEMNAME") access("RL" "STATEMENT_ID"="TGT" "STATEMENT_ID" AND "RL" "ACCTSTRINGDATE">SYSDATE@! AND "RL" "ACCTSTRINGDATE" IS NOT NULL) access("SRC" "QUERYID"="RL" "QUERYID" AND "SRC" "ACCTSTRINGDATE"="RL" "ACCTSTRINGDATE") filter("SRC" "ACCTSTRINGDATE"="TGT" "ACCTSTRINGDATE" AND "SRC" "ACCTSTRINGDATE">SYSDATE@! )从新的的执行计划可以看出 它的第一个NESTED LOOP果然用了最新创建的索引 下面是执行时间
复制代码 代码如下: 已用时间: : : cha138/Article/program/Oracle/201311/19032相关参考
详细讲解SQLServer索引的性能问题[6] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&nb
详细讲解SQLServer索引的性能问题[5] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&nb
详细讲解SQLServer索引的性能问题[4] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&nb
详细讲解SQLServer索引的性能问题[3] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&nb
详细讲解SQLServer索引的性能问题[2] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&nb
详细讲解SQLServer索引的性能问题[1] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&nb
分区表分区索引和全局索引 在一个表的数据超过过万条或占用G空间时建议建立分区表 create table ta(
DML性能低下其中最严重的原因之一是无用索引的存在所有SQL的插入更新和删除操作在它们需要在每一行数据被改变时修改大量索引的时候会变得更慢 许多Oracle管理人员只要看见在一个SQL查询的
现在你可以通过字符串建立索引提高性能 许多PL/SQL程序对数据进行操作通常是通过使用SQL在数据库中直接操作数据你经常还需要在PL/SQL程序本身内声明和管理数据这个程序数据可能由一些单独的值
知识大全 Microsoft SQL Server 全文索引服务 - 编程提高篇
MicrosoftSQLServer全文索引服务-编程提高篇 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看