分类: Oracle
一般情况下,select count语句很难避免走全表扫描,对于上百万行的表这个语句使用起来就比较吃力了,今天上午群里一帮oracle工程师讨论了很久,这是个很好的研究课题,我在网上找到一篇文章,贴在这应该也可以给大家起到一定的启发作用。 以下为转帖了:
select count(*) from t1;这句话比较简单,但很有玄机!对这句话运行的理解,反映了你对数据库的理解深度!建立实验的大表他t1
SQL> conn scott/tiger已连接。SQL> drop table t1 purge;
表已删除。
SQL> create table t1 as select * from emp where 0=9;
表已创建。
SQL> insert into t1 select * from emp;
已创建14行。
SQL> insert into t1 select * from t1;
已创建14行。
SQL> /
已创建28行。
SQL> /
已创建56行。
SQL> /
已创建112行。
SQL> /
已创建224行。
SQL> /
已创建448行。
SQL> /
已创建896行。
SQL> /
已创建1792行。
SQL> /
已创建3584行。
SQL> /
已创建7168行。
SQL> /
已创建14336行。
SQL> /
已创建28672行。
SQL> /
已创建57344行。
SQL> commit;
提交完成。
收集统计信息SQL> execute dbms_stats.gather_table_stats('SCOTT','T1');
PL/SQL 过程已成功完成。
SQL> SET AUTOT TRACE EXPSQL> SELECT COUNT(*) FROM T1;
执行计划-------------------------------------------------- | Id | Operation | Name | Rows | Cost (%CPU)| Time | ------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 124 (4)| 00:00:02 | | 1 | SORT AGGREGATE | | 1 | | | | 2 | TABLE ACCESS FULL| T1 | 116K| 124 (4)| 00:00:02 | -----------------------------------------------------代价为124,运行的计划为全表扫描。 SQL> DELETE T1 WHERE DEPTNO=10;
已删除24576行。
SQL> COMMIT;
提交完成。
SQL> execute dbms_stats.gather_table_stats('SCOTT','T1');
PL/SQL 过程已成功完成。
SQL> SELECT COUNT(*) FROM T1;
执行计划-----------------------------------------------------| Id | Operation | Name | Rows | Cost (%CPU)| Time | ------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 123 (3)| 00:00:02 | | 1 | SORT AGGREGATE | | 1 | | | | 2 | TABLE ACCESS FULL| T1 | 90286 | 123 (3)| 00:00:02 | -----------------------------------------------------SQL> --1.降低高水位SQL> alter table t1 move tablespace users;
表已更改。
SQL> execute dbms_stats.gather_table_stats('SCOTT','T1');
PL/SQL 过程已成功完成。
SQL> SELECT COUNT(*) FROM T1;
执行计划-----------------------------------------------------| Id | Operation | Name | Rows |Cost (%CPU)| Time | ------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 102 (3)| 00:00:02 | | 1 | SORT AGGREGATE | | 1 | | | | 2 | TABLE ACCESS FULL| T1 | 90667 | 102 (3)| 00:00:02 | ----------------------------------------------------- 代价为102,降低了
SQL> --2.修改pctfreeSQL> alter table t1 pctfree 0;
表已更改。
SQL> alter table t1 move tablespace users;
表已更改。
SQL> execute dbms_stats.gather_table_stats('SCOTT','T1');
PL/SQL 过程已成功完成。
SQL> SELECT COUNT(*) FROM T1;
执行计划---------------------------------------------------------- Plan hash value: 3724264953 ------------------------------------------------------------------- | Id | Operation | Name | Rows | Cost (%CPU)| Time | ------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 92 (4)| 00:00:02 | | 1 | SORT AGGREGATE | | 1 | | | | 2 | TABLE ACCESS FULL| T1 | 91791 | 92 (4)| 00:00:02 | ------------------------------------------------------------------- 代价为92,降低了10%
SQL> --3.参数db_file_multiblock_read_count=64SQL> --4.建立b*tree类型的索引SQL> create index i1 on t1(empno);
索引已创建。
SQL> execute dbms_stats.gather_index_stats('SCOTT','I1');
PL/SQL 过程已成功完成。
SQL> SELECT COUNT(*) FROM T1;
执行计划---------------------------------------------------------- Plan hash value: 3724264953 ------------------------------------------------------------------- | Id | Operation | Name | Rows | Cost (%CPU)| Time | ------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 92 (4)| 00:00:02 | | 1 | SORT AGGREGATE | | 1 | | | | 2 | TABLE ACCESS FULL| T1 | 91791 | 92 (4)| 00:00:02 | ------------------------------------------------------------------- 为什么没有使用我们建立的索引,因为null不进入普通的索引!
SQL> alter table t1 modify(empno not null);
表已更改。
SQL> SELECT COUNT(*) FROM T1;
执行计划---------------------------------------------------------- Plan hash value: 129980005 ---------------------------------------------------------------------- | Id | Operation | Name | Rows | Cost (%CPU)| Time | ---------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 36 (6)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | | | | 2 | INDEX FAST FULL SCAN| I1 | 91791 | 36 (6)| 00:00:01 | ---------------------------------------------------------------------- 我们的索引起到了很大的作用!
SQL> --5.使用并行查询的特性 强制全表扫描,屏蔽索引
SQL> select /*+ full(t1) parallel(t1 2) */ COUNT(*) FROM T1;
执行计划----------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib | ----------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 51 (4)| 00:00:01 | | | | | 1 | SORT AGGREGATE | | 1 | | | | | | | 2 | PX COORDINATOR | | | | | | | | | 3 | PX SEND QC (RANDOM) | :TQ10000 | 1 | | | Q1,00 | P->S | QC(RAND) | | 4 | SORT AGGREGATE | | 1 | | | Q1,00 | PCWP | | | 5 | PX BLOCK ITERATOR | | 91791 | 51 (4)| 00:00:01 | Q1,00 | PCWC| | | 6 | TABLE ACCESS FULL| T1 | 91791 | 51 (4)| 00:00:01 | Q1,00 | PCWP | | -----------------------------------------------------------------------------------------------并行度越高,代价越低
SQL> alter table t1 parallel 4;
表已更改。也可以通过使用表的属性来定义并行度,但是影响比较大,不如语句级别限制并行!
SQL> select count(*) from t1;
执行计划-----------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Cost (%CPU)| Time | TQ |IN-OUT| PQDistrib | ---------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 25 (0)| 00:00:01 | | | | | 1 | SORT AGGREGATE | | 1 | | | | | | | 2 | PX COORDINATOR | | | | | | | | | 3 | PX SEND QC (RANDOM) | :TQ10000 | 1 | | | Q1,00 | P->S | QC(RAND) | | 4 | SORT AGGREGATE | | 1 | | | Q1,00 | PCWP | | | 5 | PX BLOCK ITERATOR | | 91791 | 25 (0)| 00:00:01 | Q1,00 | PCWC | | | 6 | TABLE ACCESS FULL| T1 | 91791 | 25 (0)| 00:00:01 | Q1,00 | PCWP | | ---------------------------------------------------------------------------------------------代价为25,代价比两个的又少一半!
SQL> --6.建立位图索引来避免全表扫描SQL> create bitmap index i2 on t1(deptno);
索引已创建。
SQL> execute dbms_stats.gather_index_stats('SCOTT','I2');
PL/SQL 过程已成功完成。
SQL> select count(*) from t1;
执行计划---------------------------------------------------------- Plan hash value: 3738977131 ------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Cost (%CPU)| Time | ------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | 4 (0)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | | | | 2 | BITMAP CONVERSION COUNT | | 91791 | 4 (0)| 00:00:01 | | 3 | BITMAP INDEX FAST FULL SCAN| I2 | | | | ------------------------------------------------------------------------------
SQL> alter index i2 parallel 4;
索引已更改。
SQL> select count(*) from t1;执行计划----------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib | ----------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 2 (0)| 00:00:01 | | | | | 1 | SORT AGGREGATE | | 1 | | | | | | | 2 | PX COORDINATOR | | | | | | | | | 3 | PX SEND QC (RANDOM) | :TQ10000 | 1 | | | Q1,00 | P->S | QC (RAND) | | 4 | SORT AGGREGATE | | 1 | | | Q1,00 | PCWP | | | 5 | PX BLOCK ITERATOR | | 91791 | 2 (0)| 00:00:01 | Q1,00 |PCWC | | | 6 | BITMAP CONVERSION COUNT | | 91791 | 2 (0)| 00:00:01 | Q1,00 |PCWP | | | 7 | BITMAP INDEX FAST FULL SCAN| I2 | | | | Q1,00 | PCWP | | --------------------------------------------------------------------------------------------代价为2,原来为124,优化无止境呀!只有你把握原理,一切尽在掌握!
转载于:https://www.cnblogs.com/woxing/p/3255143.html