Faster alternative in Oracle to SELECT COUNT(*) FROM sometable

前端 未结 11 523
被撕碎了的回忆
被撕碎了的回忆 2020-11-29 21:57

I\'ve notice that in Oracle, the query

SELECT COUNT(*) FROM sometable;

is very slow for large tables. It seems like the database it actual

相关标签:
11条回答
  • 2020-11-29 22:31

    You can create a fast refresh materialized view to store the count.

    Example:

    create table sometable (
    id number(10) not null primary key
    , name varchar2(100) not null);
    
    create materialized view log on sometable with rowid including new values;
    
    create materialized view sometable_count
    refresh on commit
    as
    select count(*) count
    from   sometable;
    
    insert into sometable values (1,'Raymond');
    insert into sometable values (2,'Hans');
    
    commit;
    
    select count from sometable_count; 
    

    It will slow mutations on table sometable a bit but the counting will become a lot faster.

    0 讨论(0)
  • 2020-11-29 22:33

    This works great for large tables.

    SELECT NUM_ROWS FROM ALL_TABLES WHERE TABLE_NAME = 'TABLE_NAME_IN_UPPERCASE';
    

    For small to medium size tables, following will be ok.

    SELECT COUNT(Primary_Key) FROM table_name;
    

    Cheers,

    0 讨论(0)
  • 2020-11-29 22:34

    Option 1: Have an index on a non-null column present that can be used for the scan. Or create a function-based index as:

    create index idx on t(0);
    

    this can then be scanned to give the count.

    Option 2: If you have monitoring turned on then check the monitoring view USER_TAB_MODIFICATIONS and add/subtract the relevant values to the table statistics.

    Option 3: For a quick estimate on large tables invoke the SAMPLE clause ... for example ...

    SELECT 1000*COUNT(*) FROM sometable SAMPLE(0.1); 
    

    Option 4: Use a materialized view to maintain the count(*). Powerful medicine though.

    um ...

    0 讨论(0)
  • 2020-11-29 22:38

    You could use COUNT(1) instead

    0 讨论(0)
  • 2020-11-29 22:40

    You can have better performance by using the following method:

    SELECT COUNT(1) FROM (SELECT /*+FIRST_ROWS*/ column_name 
    FROM table_name 
    WHERE column_name = 'xxxxx' AND ROWNUM = 1);
    
    0 讨论(0)
  • 2020-11-29 22:42

    If the table has an index on a NOT NULL column the COUNT(*) will use that. Otherwise it is executes a full table scan. Note that the index doesn't have to be UNIQUE it just has to be NOT NULL.

    Here is a table...

    SQL> desc big23
     Name                                      Null?    Type
     ----------------------------------------- -------- ---------------------------
     PK_COL                                    NOT NULL NUMBER
     COL_1                                              VARCHAR2(30)
     COL_2                                              VARCHAR2(30)
     COL_3                                              NUMBER
     COL_4                                              DATE
     COL_5                                              NUMBER
     NAME                                               VARCHAR2(10)
    
    SQL>
    

    First we'll do a count with no indexes ....

    SQL> explain plan for
      2      select count(*) from big23
      3  /
    
    Explained.
    
    SQL> select * from table(dbms_xplan.display)
      2  /
    select * from table)dbms_xplan.display)
    
    PLAN_TABLE_OUTPUT
    --------------------------------------------------------------------
    Plan hash value: 983596667
    
    --------------------------------------------------------------------
    | Id  | Operation          | Name  | Rows  | Cost (%CPU)| Time     |
    --------------------------------------------------------------------
    |   0 | SELECT STATEMENT   |       |     1 |  1618   (1)| 00:00:20 |
    |   1 |  SORT AGGREGATE    |       |     1 |            |          |
    |   2 |   TABLE ACCESS FULL| BIG23 |   472K|  1618   (1)| 00:00:20 |
    --------------------------------------------------------------------
    
    Note
    
    PLAN_TABLE_OUTPUT
    --------------------------------------------------------------------
       - dynamic sampling used for this statement
    
    13 rows selected.
    
    SQL>
    

    No we create an index on a column which can contain NULL entries ...

    SQL> create index i23 on big23(col_5)
      2  /
    
    Index created.
    
    SQL> delete from plan_table
      2  /
    
    3 rows deleted.
    
    SQL> explain plan for
      2      select count(*) from big23
      3  /
    
    Explained.
    
    SQL> select * from table(dbms_xplan.display)
      2  /
    
    PLAN_TABLE_OUTPUT
    --------------------------------------------------------------------
    Plan hash value: 983596667
    
    --------------------------------------------------------------------
    | Id  | Operation          | Name  | Rows  | Cost (%CPU)| Time     |
    --------------------------------------------------------------------
    |   0 | SELECT STATEMENT   |       |     1 |  1618   (1)| 00:00:20 |
    |   1 |  SORT AGGREGATE    |       |     1 |            |          |
    |   2 |   TABLE ACCESS FULL| BIG23 |   472K|  1618   (1)| 00:00:20 |
    --------------------------------------------------------------------
    
    Note
    
    PLAN_TABLE_OUTPUT
    --------------------------------------------------------------------
       - dynamic sampling used for this statement
    
    13 rows selected.
    
    SQL>
    

    Finally let's build the index on the NOT NULL column ....

    SQL> drop index i23
      2  /
    
    Index dropped.
    
    SQL> create index i23 on big23(pk_col)
      2  /
    
    Index created.
    
    SQL> delete from plan_table
      2  /
    
    3 rows deleted.
    
    SQL> explain plan for
      2      select count(*) from big23
      3  /
    
    Explained.
    
    SQL> select * from table(dbms_xplan.display)
      2  /
    
    PLAN_TABLE_OUTPUT
    ---------------------------------------------------------------------
    Plan hash value: 1352920814
    
    ----------------------------------------------------------------------
    | Id  | Operation             | Name | Rows  | Cost (%CPU)| Time     |
    ----------------------------------------------------------------------
    |   0 | SELECT STATEMENT      |      |     1 |   326   (1)| 00:00:04 |
    |   1 |  SORT AGGREGATE       |      |     1 |            |          |
    |   2 |   INDEX FAST FULL SCAN| I23  |   472K|   326   (1)| 00:00:04 |
    ----------------------------------------------------------------------
    
    Note
    
    PLAN_TABLE_OUTPUT
    ----------------------------------------------------------------------
       - dynamic sampling used for this statement
    
    13 rows selected.
    
    SQL>
    
    0 讨论(0)
提交回复
热议问题