我们假设没有为表T定义主键。在这种情况下,如何快速/有效地为这些数据库计算T中的所有行 - Oracle 11g,MySql,Mssql?
似乎count(*)和count(column_name)分别可能很慢且不准确。以下似乎是最快,最可靠的方法 -
select count(rowid) from MySchema.TableInMySchema;
您能否告诉我上述陈述是否也有任何缺点?如果它是好的,那么我们是否有类似的mysql和mssql语句?
提前致谢。
来源 - http://www.thewellroundedgeek.com/2007/09/most-people-use-oracle-count-function.html
答案 0 :(得分:3)
count(column_name)
不 不准确,它只是与count(*)完全不同的东西。
SQL标准将count(column_name)
定义为等同于count(*) where column_name IS NOT NULL
。如果column_name可以为空,那么结果必然是不同的。
在Oracle(以及可能还有其他DBMS)中,count(*)
将使用非空列上的可用索引来计算行数(例如PK索引)。所以它就像fas一样
此外,没有类似于SQL Server或MySQL中的rowid(在PostgreSQL中它将是ctid
)。
请使用count(*)
。这是获得行数的最佳选择。如果有足够的索引,让DBMS在后台进行任何优化。
修改
关于Oracle如何自动使用索引以及如何减少数据库完成的工作量的快速演示:
测试表的设置:
create table foo (id integer not null, c1 varchar(2000), c2 varchar(2000));
insert into foo (id, c1, c2)
select lvl, c1, c1 from
(
select level as lvl, dbms_random.string('A', 2000) as c1
from dual
connect by level < 10000
);
生成10000行,每行填满一些空格,以确保表格具有真实的大小。
现在在SQL * Plus中运行以下命令:
SQL> set autotrace traceonly explain statistics; SQL> select count(*) from foo; Execution Plan ---------------------------------------------------------- Plan hash value: 1342139204 ------------------------------------------------------------------- | Id | Operation | Name | Rows | Cost (%CPU)| Time | ------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 2740 (1)| 00:00:33 | | 1 | SORT AGGREGATE | | 1 | | | | 2 | TABLE ACCESS FULL| FOO | 9999 | 2740 (1)| 00:00:33 | ------------------------------------------------------------------- Statistics ---------------------------------------------------------- 181 recursive calls 0 db block gets 10130 consistent gets 0 physical reads 0 redo size 430 bytes sent via SQL*Net to client 420 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 5 sorts (memory) 0 sorts (disk) 1 rows processed SQL>
正如你所看到的那样,在桌子上进行了全表扫描,这需要10130“IO操作”(我知道这不是正确的术语,但为了演示它应该对某人来说是一个很好的解释从来没有见过这个)
现在我在该列上创建一个索引并再次运行count(*):
SQL> create index i1 on foo (id); Index created. SQL> select count(*) from foo; Execution Plan ---------------------------------------------------------- Plan hash value: 129980005 ---------------------------------------------------------------------- | Id | Operation | Name | Rows | Cost (%CPU)| Time | ---------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 7 (0)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | | | | 2 | INDEX FAST FULL SCAN| I1 | 9999 | 7 (0)| 00:00:01 | ---------------------------------------------------------------------- Statistics ---------------------------------------------------------- 1 recursive calls 0 db block gets 27 consistent gets 21 physical reads 0 redo size 430 bytes sent via SQL*Net to client 420 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed SQL>
正如你所看到的那样,Oracle确实在(非null!)列上使用了索引,并且IO的数量急剧下降(从10130到27 - 不是我称之为“非常低效的 “)。
“物理读取”源于索引刚刚创建并且尚未进入缓存的事实。
我希望其他DBMS能够应用相同的优化。
答案 1 :(得分:1)
在Oracle中,COUNT(*)
效率最高。实际上,COUNT(rowid)
,COUNT(1)
或COUNT('fuzzy bunny')
可能同样有效。但如果存在差异,COUNT(*)
会更有效率。
答案 2 :(得分:0)
我 EVER 使用SELECT COUNT(1) FROM anything;
,而不是星号......
有些人认为,当使用“1”作为静态标量时,mysql使用星号来调用查询优化器并忽略任何优化...
imho,这很简单,因为你没有使用任何变量,而且很明显,你只计算所有行。