web-dev-qa-db-ja.com

SQL count(*)パフォーマンス

2000万行を超えるSQLテーブルBookChaptersがあります。クラスター化された主キー(bookChapterID)があり、他のキーやインデックスはありません。次のクエリの実行にはミリ秒かかります

_if (select count(*) from BookChapters) = 0
...
_

ただし、そのように変更すると10分以上かかります

_if (select count(*) from BookChapters) = 1
...
_

または

_if (select count(*) from BookChapters) > 1
...
_

何故ですか? select count(*)を取得して高速に実行するにはどうすればよいですか?

35
danmiao

Mikael Erikssonが、最初のクエリが高速である理由を説明しています。

SQLサーバーは、if exists(select * from BookChapters)に最適化します。そのため、テーブル内のすべての行をカウントする代わりに、1つの行の存在を探します。

他の2つのクエリでは、SQL Serverは次のルールを使用します。 SELECT COUNT(*)などのクエリを実行するには、SQL Serverは最も狭いnon-clusteredインデックスを使用して行をカウントします。テーブルに非クラスター化インデックスがない場合、テーブルをスキャンする必要があります。

また、テーブルにclusteredインデックスがある場合、次のクエリを使用してカウントをさらに速く取得できます(このサイトから借用 Get Row Counts速い!

--SQL Server 2005/2008
SELECT OBJECT_NAME(i.id) [Table_Name], i.rowcnt [Row_Count]
FROM sys.sysindexes i WITH (NOLOCK)
WHERE i.indid in (0,1)
ORDER BY i.rowcnt desc

--SQL Server 2000
SELECT OBJECT_NAME(i.id) [Table_Name], i.rows [Row_Count]
FROM sysindexes i (NOLOCK)
WHERE i.indid in (0,1)
ORDER BY i.rows desc

Sysindexesシステムテーブルを使用します。詳細情報はこちら SQL Server 20SQL Server 2005SQL Server 2008SQL Server 2012

ここに別のリンクがあります なぜSELECT COUNT(*)が非常に遅いのですか? 別のソリューションと。表を右クリックしてプロパティを選択すると、Microsoftが行数をすばやく表示するために使用する手法を示しています。

select sum (spart.rows)
from sys.partitions spart
where spart.object_id = object_id(’YourTable’)
and spart.index_id < 2

テーブルの数に関係なく、これはすぐに返されることに気付くはずです。

それでもSQL 2000を使用している場合は、sysindexesテーブルを使用して番号を取得できます。

select max(ROWS)
from sysindexes
where id = object_id(’YourTable’)

この数は、SQLがsysindexesテーブルを更新する頻度に応じてわずかにずれることがありますが、通常は現在の(または少なくとも十分に近い)ものです。

53

行数のみを知りたい場合はこれを試してください:

exec sp_spaceused [TABLE_NAME]
12
ehsandotnet

クエリの実行計画を見ると、何が起こっているのかがわかります。

最初のクエリif (select count(*) from BookChapters) = 0は、if exists(select * from BookChapters)と同じものとしてクエリオプティマイザーによって認識されます。 SQL Serverは、少なくとも1つの行が存在する場合に式が真であることを認識しているため、テーブル内のすべての行をカウントするのではなく、1つの行の存在を探します。

他のクエリではそれほど賢くなく、式がtrueまたはfalseに評価されるかどうかを判断する前に、テーブル内の行数をカウントする必要があります。

7
Mikael Eriksson

クエリselect count(BookChapterId) from BookChapterTableを検討しましたか? -ここで、 `BookChapterIdは非クラスター化インデックスです。それはそれをはるかに高速に実行する必要があります。

テーブルの使用方法とアクセスされる行によっては、非クラスター化インデックスに対するクエリが重要なポイントになる場合があります。MDSNからいくつかのポイントを取りました。

  • 非クラスター化インデックスを作成する前に、データへのアクセス方法を理解してください。以下に対して非クラスター化インデックスの使用を検討してください。
  • 次のような多数の個別の値を含む列
    姓と名の組み合わせ(クラスター化インデックスが他の列に使用されている場合)。次のような個別の値が非常に少ない場合
    1および0のみ。ほとんどのクエリはテーブルを使用するためインデックスを使用しません。
    スキャンは通常より効率的です。
  • 大きな結果セットを返さないクエリ。
  • クエリの検索条件に頻繁に関与する列(WHERE
    clause)完全一致を返します。
  • 結合とグループ化が頻繁に必要な意思決定支援システムアプリケーション。結合操作とグループ化操作に関係する列に複数の非クラスター化インデックスを作成し、外部キー列にクラスター化インデックスを作成します。
  • 特定のクエリの1つのテーブルのすべての列をカバーします。これにより、テーブルまたはクラスター化インデックスに完全にアクセスする必要がなくなります。
5
EL Yusubov

テーブルに複数の行がある場合、検出する必要がある場合は、これを試してください:

if (SELECT COUNT(*) FROM (SELECT TOP 2 * FROM BookChapters) AS b) > 1
2
WURMi