计算任何数据库表中行的最快方法?

时间:2012-08-26 07:55:21

标签: mysql database sql-server-2008 oracle11g

我们假设没有为表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

3 个答案:

答案 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,这很简单,因为你没有使用任何变量,而且很明显,你只计算所有行。