count(column_name)
不正確ではなく、単にcount(*)とはまったく異なるものです。
SQL標準ではcount(column_name)
、と同等と定義されていcount(*) where column_name IS NOT NULL
ます。column_nameがnull許容の場合、結果は異なるものになります。
Oracle(および場合によっては他のDBMSも)では、count(*)
null以外の列で使用可能なインデックスを使用して行をカウントします(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> fooからcount(*)を選択します。
実行計画
-------------------------------------------------- --------
計画ハッシュ値:1342139204
-------------------------------------------------- -----------------
| Id | 操作| 名前| 行| コスト(%CPU)| 時間|
-------------------------------------------------- -----------------
| 0 | ステートメントの選択| | 1 | 2740(1)| 00:00:33 |
| 1 | ソートアグリゲート| | 1 | | |
| 2 | テーブルアクセスがいっぱい| FOO | 9999 | 2740(1)| 00:00:33 |
-------------------------------------------------- -----------------
統計学
-------------------------------------------------- --------
181回の再帰呼び出し
0デシベルブロックは取得します
10130一貫した取得
0物理読み取り
0やり直しサイズ
SQL*Net経由でクライアントに送信される430バイト
クライアントからSQL*Net経由で受信した420バイト
クライアントとの間の2つのSQL*Netラウンドトリップ
5ソート(メモリ)
0ソート(ディスク)
1行が処理されました
SQL>
ご覧のとおり、10130の「IO操作」を必要とするテーブルで全表スキャンが実行されます(これは正しい用語ではないことはわかっていますが、デモのために、これを見たことがない人にとっては十分な説明になるはずです。前)
次に、その列にインデックスを作成し、count(*)を再度実行します。
SQL> foo(id);にインデックスi1を作成します。
インデックスが作成されました。
SQL> fooからcount(*)を選択します。
実行計画
-------------------------------------------------- --------
計画ハッシュ値:129980005
-------------------------------------------------- --------------------
| Id | 操作| 名前| 行| コスト(%CPU)| 時間|
-------------------------------------------------- --------------------
| 0 | ステートメントの選択| | 1 | 7(0)| 00:00:01 |
| 1 | ソートアグリゲート| | 1 | | |
| 2 | INDEX FAST FULL SCAN | I1 | 9999 | 7(0)| 00:00:01 |
-------------------------------------------------- --------------------
統計学
-------------------------------------------------- --------
1回の再帰呼び出し
0デシベルブロックは取得します
27の一貫した取得
21回の物理読み取り
0やり直しサイズ
SQL*Net経由でクライアントに送信される430バイト
クライアントからSQL*Net経由で受信した420バイト
クライアントとの間の2つのSQL*Netラウンドトリップ
0ソート(メモリ)
0ソート(ディスク)
1行が処理されました
SQL>
ご覧のとおり、Oracleは(nullではない!)列のインデックスを使用し、IOの量は大幅に減少しました(10130から27に-私が「非常に非効率的」と呼ぶものではありません)。
「物理読み取り」は、インデックスが作成されたばかりで、まだキャッシュにないという事実に由来します。
他のDBMSが同じ最適化を適用することを期待します。