select count的优化 2011-08-02 12:01:36

分类: 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 EXP
SQL> 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.修改pctfree
SQL> 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=64
SQL> --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,优化无止境呀!
只有你把握原理,一切尽在掌握!

select count的优化的更多相关文章

  1. SQL Select count(*)和Count(1)的区别和执行方式及SQL性能优化

    SQL性能优化:http://www.cnblogs.com/CareySon/category/360333.html Select count(*)和Count(1)的区别和执行方式 在SQL S ...

  2. 从多表连接后的select count(*)看待SQL优化

    从多表连接后的select count(*)看待SQL优化 一朋友问我,以下这SQL能直接改写成select count(*) from a吗? SELECT COUNT(*) FROM a LEFT ...

  3. SQL优化之SELECT COUNT(*)

    前言 SQL优化之SQL 进阶技巧(上) SQL优化之SQL 进阶技巧(下)中提到使用以下 sql 会导致慢查询 SELECT COUNT(*) FROM SomeTable SELECT COUNT ...

  4. select count(*)优化 快速得到总记录数

    1.select count(*) from table_name 比select count(主键列) from table_name和select count(1) from table_name ...

  5. Select count(*)和Count(1)的区别和执行方式

        在SQL Server中Count(*)或者Count(1)或者Count([列])或许是最常用的聚合函数.很多人其实对这三者之间是区分不清的.本文会阐述这三者的作用,关系以及背后的原理.   ...

  6. SQLSERVER 里SELECT COUNT(1) 和SELECT COUNT(*)哪个性能好?

    SQLSERVER 里SELECT COUNT(1) 和SELECT COUNT(*)哪个性能好? 今天遇到某人在我以前写的一篇文章里问到 如果统计信息没来得及更新的话,那岂不是统计出来的数据时错误的 ...

  7. mysql技巧之select count的比较

        在工作过程中,时不时会有开发咨询几种select count()的区别,我总会告诉他们使用select count(*) 就好.下文我会展示几种sql的执行计划来说明为啥是这样.   1.测试 ...

  8. select count(*) 底层究竟做了什么?

    阅读本文大概需要 6.6 分钟. SELECT COUNT( * ) FROM t是个再常见不过的 SQL 需求了.在 MySQL 的使用规范中,我们一般使用事务引擎 InnoDB 作为(一般业务)表 ...

  9. mysql 查询优化 ~ select count 知多少

    一 简介:今天咱们来聊聊mysql的查询总数 二 具体介绍 1 从引擎层面说 myisam  myisam的扫描总行数是非常快的,这是因为myisam会将表的总行数存储起来,定期维护,但是注意,一旦加 ...

随机推荐

  1. 《锋利的jQuery》心得笔记--Four Sections

    第八章 1.    当父元素设置position:relative的时候,子元素设置position:absolute.这个子元素设置在父元素的任何位置. 第九章 1.    对可视区进行纠正,通知浏 ...

  2. java集合(交集,并集,差集)

    说明:这里没有求差集的代码,有了交集和并集,差集=并集-交集       package com; import java.util.ArrayList; import java.util.HashS ...

  3. Codevs 1380 没有上司的舞会

    时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题目描述 Description Ural大学有N个职员,编号为1~N.他们有从属关系,也就是说他们的关系就 ...

  4. Ubuntu 14.04下java开发环境的搭建--3--Tomcat及MySQL的安装

    前面两篇文章,已经说明了JDK和Eclipse 的安装方法,下面简单说一下,Tomcat及MySQL的安装方法. Tomcat的安装. 在合适的地方解压apache-tomcat-6.0.39.tar ...

  5. Placeholdem文本域占位符符号标识JavaScript插件

    Placeholdem是文本域占位符符号标识的一个JavaScript插件.占位符的值将逐步删除焦点文字,并在焦点离开逐步恢复. 在线demo:http://placeholdem.jackrugil ...

  6. 【转】HttpServletRequest.getParameter() &HttpServletRequest.getAttribute() 区别

    Ref: HttpServletRequest的getParameter和getAttribute方法有什么区别 具体如下几点: (1)HttpServletRequest类有setAttribute ...

  7. AngularJS(17)-Angular小程序

    现在可以开始创建您的第一个 AngularJS 应用程序,一个 AngularJS 单页 Web 应用. <!DOCTYPE html> <html lang="en&qu ...

  8. Mod 与 RequireJS/SeaJS 的那些事

    本文的目的是为了能大让家更好的认识 Mod,之所以引入 RequireJS/SeaJS 的对比主要是应大家要求更清晰的对比应用场景,并不是为了比较出孰胜孰劣,RequireJS 和 SeaJS 都是模 ...

  9. sql拆分查询

    有这样一个需求: 临时表sql: create table #AA ( ID int, Name nvarchar(20) ) insert #AA select 1,'苏州/上海/温州' union ...

  10. c#中的结构与枚举

    结构 与c++不同的是,结构应该定义在命名空间或者类里面,成员变量叫字段,字段并且有访问控制符,每个字段前要加一个下划线 例子 using System; using System.Collectio ...