我在Oracle中注意到了查询
SELECT COUNT(*) FROM sometable;
对于大型表来说非常慢。它似乎是数据库,它实际上遍历每一行并一次递增一个计数器。我认为表中某处有一个计数器表有多少行。
因此,如果我想检查Oracle中表中的行数,那么最快的方法是什么?
答案 0 :(得分:53)
如果您只想粗略估算一下,可以从样本中推断:
SELECT COUNT(*) * 100 FROM sometable SAMPLE (1);
为了提高速度(但精度较低),您可以减小样本量:
SELECT COUNT(*) * 1000 FROM sometable SAMPLE (0.1);
如果速度更快(但精度更差),您可以使用逐块采样:
SELECT COUNT(*) * 100 FROM sometable SAMPLE BLOCK (1);
答案 1 :(得分:44)
这适用于大型表格。
SELECT NUM_ROWS FROM ALL_TABLES WHERE TABLE_NAME = 'TABLE_NAME_IN_UPPERCASE';
对于中小型表,以下都可以。
SELECT COUNT(Primary_Key) FROM table_name;
干杯,
答案 2 :(得分:27)
想一想:数据库真的必须去每一行才能做到这一点。 在多用户环境中,我的COUNT(*)
可能与您的COUNT(*)
不同。为每个会话设置一个不同的计数器是不切实际的,因此你可以按字面计算行数。大多数情况下,你的查询中都会有WHERE子句或JOIN,所以你的假设计数器具有实用价值。
有一些方法可以加快速度:如果在NOT NULL列上有一个INDEX,Oracle将计算索引的行而不是表。在适当的关系模型中,所有表都有一个主键,因此COUNT(*)
将使用主键的索引。
位图索引具有NULL行的条目,因此如果有一个位图索引,COUNT(*)将使用位图索引。
答案 3 :(得分:13)
如果表在NOT NULL列上有索引,则COUNT(*)将使用该列。否则,它将执行全表扫描。请注意,索引不必是UNIQUE,它必须是非NULL。
这是一张表......
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>
首先我们要做一个没有索引的计数......
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>
不,我们在列上创建一个可以包含NULL条目的索引......
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>
最后让我们在NOT NULL列上构建索引....
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>
答案 4 :(得分:7)
选项1:在非空列上有一个可用于扫描的索引。或者创建基于函数的索引:
create index idx on t(0);
然后可以扫描这个以计算。
选项2:如果您已启用监控,请检查监控视图USER_TAB_MODIFICATIONS并将相关值添加/减去表统计信息。
选项3:对大型表的快速估计调用SAMPLE子句...例如......
SELECT 1000*COUNT(*) FROM sometable SAMPLE(0.1);
选项4:使用物化视图来维护计数(*)。虽然是强大的药物。
嗯......答案 5 :(得分:5)
您可以创建快速刷新物化视图来存储计数。
示例:
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;
它可以减缓桌面上的突变,但计数会变得更快。
答案 6 :(得分:3)
获得桌子计数的最快方法正是你所做的。你可以做的任何技巧都是Oracle不知道的。
有些事你没有告诉我们。也就是为什么你认为这应该更快?
例如:
我承认我会在41秒内不开心,但为什么你觉得它应该更快?如果你告诉我们这张桌子有180亿行并且是你在2001年从车库出售的笔记本电脑上运行的话,41秒可能并不是那么好“除非你得到更好的硬件”。但是,如果你说你使用的是Oracle 9并且你去年夏天运行了统计数据,你可能会得到不同的建议。
答案 7 :(得分:1)
2016年4月发布了Ask Tom的相关答案。
如果您有足够的服务器电源,则可以执行
select /*+ parallel */ count(*) from sometable
如果您刚刚接近,可以这样做:
select 5 * count(*) from sometable sample block (10);
另外,如果有
- 一个不包含空值的列,但未定义为NOT NULL和
- 该列上有索引
醇> 你可以尝试:select /*+ index_ffs(t) */ count(*) from sometable t where indexed_col is not null
答案 8 :(得分:0)
这对我来说很好
select owner, table_name, nvl(num_rows,-1)
from all_tables
--where table_name in ('cats', 'dogs')
order by nvl(num_rows,-1) desc
来自https://livesql.oracle.com/apex/livesql/file/content_EPJLBHYMPOPAGL9PQAV7XH14Q.html
答案 9 :(得分:-1)
使用以下方法可以获得更好的性能:
SELECT COUNT(1) FROM (SELECT /*+FIRST_ROWS*/ column_name
FROM table_name
WHERE column_name = 'xxxxx' AND ROWNUM = 1);
答案 10 :(得分:-4)
您可以使用COUNT(1)代替