サイトアイコン こじりふぁ

COUNT(*)とCOUNT(1)の性能検証・1回目

SELECT COUNT(*)は処理速度が遅くなるから、SELECT COUNT(1)を使った方が良いと聞きます。

SELECT COUNT(*)で全カラムを指定するよりも、SELECT COUNT(1)を使って、Praimary Key(インデックス)である1カラム目を指定した方が速いという理屈は理解できます。

そこでですが、SELECT COUNT(1)は本当に処理速度が速いのか検証してみました。

SELECT COUNT(*)とSELECT COUNT(1)の性能検証

TB_MAINテーブルには100万件のレコードが登録されており2カラムあります。

TB_MAINテーブルの1カラム目(ID)はPRAYMARY_KEYです。

性能測定なのでクエリの実行前に共有プールのクリアとデータベース・バッファ・キャッシュのクリアもしています。

DESC TB_MAIN;

名前     NULL?    型
-------- -------- ------------------
ID       NOT NULL NUMBER(8)
NAME              VARCHAR2(10 CHAR)

SELECT COUNT(*) FROM TB_MAIN; COUNT(*) ---------- 1000000 経過: 00:00:03.16
SELECT COUNT(1) FROM TB_MAIN; COUNT(1) ---------- 1000000 経過: 00:00:04.43

試してみたらSELECT COUNT(1)の方が遅いですね。それぞれの実行計画も確認しました。

SELECT COUNT(*)の実行計画と統計

SELECT COUNT(*) FROM TB_MAIN;

経過: 00:00:00.10

実行計画
----------------------------------------------------------
Plan hash value: 3829837348

-----------------------------------------------------------------------------
| Id  | Operation             | Name        | Rows  | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |             |     1 |   571   (1)| 00:00:07 |
|   1 |  SORT AGGREGATE       |             |     1 |            |          |
|   2 |   INDEX FAST FULL SCAN| SYS_C007642 |  1000K|   571   (1)| 00:00:07 |
-----------------------------------------------------------------------------


統計
----------------------------------------------------------
1 recursive calls
0 db block gets 2101 consistent gets 0 physical reads 0 redo size 549 bytes sent via SQL*Net to client 524 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed

SELECT COUNT(1)の実行計画と統計

SELECT COUNT(1) FROM TB_MAIN;

経過: 00:00:00.09

実行計画
----------------------------------------------------------
Plan hash value: 3829837348

-----------------------------------------------------------------------------
| Id  | Operation             | Name        | Rows  | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |             |     1 |   571   (1)| 00:00:07 |
|   1 |  SORT AGGREGATE       |             |     1 |            |          |
|   2 |   INDEX FAST FULL SCAN| SYS_C007642 |  1000K|   571   (1)| 00:00:07 |
-----------------------------------------------------------------------------


統計
----------------------------------------------------------
0 recursive calls
0 db block gets 2101 consistent gets 0 physical reads 0 redo size 549 bytes sent via SQL*Net to client 524 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed

実行計画はどちらも同じですが、統計はSELECT COUNT(*)の場合、recursive callsが1となっており、SELECT COUNT(1)の場合、recursive callsが0となっています。

recursive calls(再帰的コールの回数)の数値が高ければ、遅いSQLになると思っていましたが、recursive callsの数値が高ければ、速くなるという不思議な結果となりました。

SELECT COUNT(*)にした方がORACLEオプティマイザがSQLを最適化してくれているという考え方もできますが、どうなんでしょうか!?

結果は少し納得ができなかったので、次回はデータ件数やカラム数を増やして検証していきたいと思います。

以上です。