0

テーブルTに主キーが定義されていないと仮定します。その場合、これらのデータベース(Oracle 11g、MySql、Mssql)のTのすべての行をすばやく効率的にカウントするにはどうすればよいですか。

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

4

3 に答える 3

3

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が同じ最適化を適用することを期待します。

于 2012-08-26T08:03:11.023 に答える
1

Oracleでは、COUNT(*)が最も効率的です。現実的にCOUNT(rowid)は、、、またはは同等に効率的である可能性がありますCOUNT(1)COUNT('fuzzy bunny')ただし、違いがある場合は、COUNT(*)より効率的になります。

于 2012-08-26T07:59:32.287 に答える
0

アスタリスクの代わりに、を使用するSELECT COUNT(1) FROM anything;ことはありません...

一部の人々は、mysqlがアスタリスクを使用してクエリオプティマイザーを呼び出し、静的スカラーとして「1」を使用する場合は最適化を無視するという意見です。

imho、これは簡単です。変数を使用せず、すべての行のみをカウントすることは明らかだからです。

于 2012-08-26T07:59:07.050 に答える