2012-06-21 132 views
25

私は20万以上の行を持つSQLテーブルBookChaptersを持っています。クラスター化された主キー(bookChapterID)があり、他のキーまたは索引はありません。それは私がそうSQLカウント(*)のパフォーマンス

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

または

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

は、なぜそれがあるようにそれを変更したときに、それが10分を引き継ぎ、

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

しかし次のクエリを実行するために、ミリ秒単位を取りますか? select count(*)をより速く実行させるにはどうすればよいですか?

+2

は一般的に「選択的に言って「テーブルからCOUNT(*) - 大きなデータで大きな問題を抱えていることがあり得る;) –

答えて

40

ミカエル・エリクソンは、最初のクエリが高速である理由怒鳴る良い説明があります。したがって、テーブルのすべての行を数える代わりに、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

ここでは別のソリューションを持つ別のリンクWhy is my SELECT COUNT(*) running so slow?です。テーブルを右クリックしてプロパティを選択すると、Microsoftが行数をすばやく表示する方法を示しています。

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

あなたが持っているテーブルの数にかかわらず、これは非常に迅速に戻ります。

あなたはまだあなたが番号を取得するために、sysindexesテーブルを使用することができますSQL 2000を使用している場合。

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

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

+1

私の提案に同意しますか? –

+1

こんにちはAleksey、あなたは天才です、私はちょうど私の新しいテーブルBookChapters2がはるかに速く返ってきたことに興味がありました、あなたが言ったように、テーブル内に非クラスタインデックスがあるので、見ました。多くの – danmiao

+1

+1素晴らしい答え - ありがとう!ただ1つの追加ポイント。照会されている表の索引/統計が最新であることを確認してください。カウントにこれらの統計を使用するので、古い統計は不正確な結果をもたらすでしょう。 – jabs

4

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

テーブルが使用され、行がキーポイントになるかもしれない非クラスタ化インデックスに対してクエリを実行、アクセス方法に応じて:私はちょうどMDSNからいくつかのポイントを取った:あなたは非クラスタ化インデックスを作成する前に

  • 、どのようにあなたのデータを理解します にアクセスしてください。

  • 姓と名の組み合わせ(クラスタ化インデックスを他の列に使用する場合は )など、多数の異なる値を含む列。
    と1と0のような明確な値がほとんどない場合、ほとんどのクエリはテーブル
    のスキャンが通常効率的であるため、インデックスを使用しません。
  • 大きな結果セットを返さないクエリ。
  • 完全一致を返すクエリ(WHERE
    句)の検索条件に頻繁に関係する列。
  • ジョインおよびグループ化が頻繁に要求される意思決定支援システムアプリケーションです( )。結合操作およびグループ化操作に関連する列 に複数のノンクラスタード・インデックスを作成し、 上のクラスタード・インデックスを作成します。
  • 特定のクエリの1つのテーブルのすべての列をカバーします。これにより、 がテーブルまたはクラスタ化インデックスにすべてアクセスすることがなくなります。 if exists(select * from BookChapters)

    SQLサーバがにそれを最適化する:

+0

こんにちはEIYusubov、私は、何の違い、まだ – danmiao

+0

を非常に遅いあなたが複合インデックスを持っている、またはあなたがそれらを再構築する必要があるかもしれ、あなたのインデックスを再検討してくださいをテストしていません。 –

+0

こんにちはEIYusubov、それはコンポジットインデックスではなく、単一の列のクラスタインデックスです、私は主キーを削除し、それを再作成しますが、違いはありません。 – danmiao

7

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

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

はあなたの他のクエリの場合には、そのスマートに、式が真または偽と評価された場合、それは決めることができます前に、テーブルの行数をカウントすることはできません。

3

あなたが検出する必要がある場合は、表に1つ以上の行がある場合は、これを試してください:あなたが行のみをカウント知りたい場合

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

はこれを試してみてください。

exec sp_spaceused [TABLE_NAME] 
関連する問題