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(*)
を取得して高速に実行するにはどうすればよいですか?
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 20 、 SQL Server 2005 、 SQL Server 2008 、 SQL 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テーブルを更新する頻度に応じてわずかにずれることがありますが、通常は現在の(または少なくとも十分に近い)ものです。
行数のみを知りたい場合はこれを試してください:
exec sp_spaceused [TABLE_NAME]
クエリの実行計画を見ると、何が起こっているのかがわかります。
最初のクエリif (select count(*) from BookChapters) = 0
は、if exists(select * from BookChapters)
と同じものとしてクエリオプティマイザーによって認識されます。 SQL Serverは、少なくとも1つの行が存在する場合に式が真であることを認識しているため、テーブル内のすべての行をカウントするのではなく、1つの行の存在を探します。
他のクエリではそれほど賢くなく、式がtrueまたはfalseに評価されるかどうかを判断する前に、テーブル内の行数をカウントする必要があります。
クエリselect count(BookChapterId) from BookChapterTable
を検討しましたか? -ここで、 `BookChapterIdは非クラスター化インデックスです。それはそれをはるかに高速に実行する必要があります。
テーブルの使用方法とアクセスされる行によっては、非クラスター化インデックスに対するクエリが重要なポイントになる場合があります。MDSNからいくつかのポイントを取りました。
テーブルに複数の行がある場合、検出する必要がある場合は、これを試してください:
if (SELECT COUNT(*) FROM (SELECT TOP 2 * FROM BookChapters) AS b) > 1