43

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

if (select count(*) from BookChapters) = 0
...

ただ、こうやって変えると10分以上かかります

if (select count(*) from BookChapters) = 1
...

また

if (select count(*) from BookChapters) > 1
...

何故ですか?どうすればselect count(*)より速く実行できるようになりますか?

4

5 に答える 5

58

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

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

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

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

--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 2000SQL 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 テーブルを更新する頻度によってはわずかにずれている可能性がありますが、通常は正しい (または少なくとも十分に近い) ものです。

于 2012-06-21T02:01:12.267 に答える
16

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

exec sp_spaceused [TABLE_NAME]
于 2014-08-01T06:16:18.100 に答える
9

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

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

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

于 2012-06-21T06:00:30.347 に答える
6

クエリを検討しましたselect count(BookChapterId) from BookChapterTable か? - ここで、`BookChapterId は非クラスター化インデックスです。これにより、実行速度が大幅に向上するはずです。

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

  • 非クラスター化インデックスを作成する前に、データがどのようにアクセスされるかを理解してください。次の目的で非クラスター化インデックスを使用することを検討してください。

  • 姓と名の組み合わせなど、多数の個別の値を含む列(クラスター化インデックスが他の列に使用されている場合)。
    1 と 0 のみなど、個別の値がほとんどない場合、
    通常はテーブル スキャンの方が効率的であるため、ほとんどのクエリはインデックスを使用しません。
  • 大きな結果セットを返さないクエリ。

  • 完全一致を返すクエリ (WHERE 句) の検索条件に頻繁に含まれる列。
  • 結合とグループ化が頻繁に必要とされる意思決定支援システム アプリケーション。結合操作とグループ化操作に関係する列に複数の非クラスター化インデックスを作成し、外部キー列にクラスター化インデックスを作成します。
  • 特定のクエリで 1 つのテーブルのすべての列をカバーします。これにより、テーブルまたはクラスター化インデックスに完全にアクセスする必要がなくなります。
于 2012-06-21T01:39:11.637 に答える
3

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

if (SELECT COUNT(*) FROM (SELECT TOP 2 * FROM BookChapters) AS b) > 1
于 2014-01-14T09:57:30.787 に答える