43

大量のデータを含むテーブルのカウントは非常に遅く、場合によっては数分かかることがあります。また、ビジー状態のサーバーでデッドロックが発生する可能性があります。実際の値を表示したいのですが、NOLOCKはオプションではありません。

私が使用しているサーバーは、SQLServer2005または2008StandardまたはEnterpriseです。SQL Serverがすべてのテーブルのカウントを維持していると想像できますが、WHERE句がない場合は、その数をかなりすばやく取得できますよね?

例えば:

SELECT COUNT(*) FROM myTable

すぐに正しい値で戻る必要があります。更新する統計に依存する必要がありますか?

4

5 に答える 5

76

非常に近い概算 (進行中のトランザクションを無視) は次のようになります。

SELECT SUM(p.rows) FROM sys.partitions AS p
  INNER JOIN sys.tables AS t
  ON p.[object_id] = t.[object_id]
  INNER JOIN sys.schemas AS s
  ON s.[schema_id] = t.[schema_id]
  WHERE t.name = N'myTable'
  AND s.name = N'dbo'
  AND p.index_id IN (0,1);

これは よりもはるかに速く返さCOUNT(*)れます。また、テーブルが十分に迅速に変更されている場合、COUNT を開始したとき (およびロックが取得されたとき) と返されたとき (ロックされたとき) の間にテーブルが変更された場合、それほど正確ではありません。解放され、すべての待機中の書き込みトランザクションがテーブルへの書き込みを許可されました)、それははるかに価値がありますか? 私はそうは思わない。

カウントしたいテーブルのサブセット (たとえばWHERE some_column IS NULL、フィルター選択されたインデックスを小さい方のセットに作成します)。したがって、これら 2 つのインデックスのいずれか:

CREATE INDEX IAmTheException ON dbo.table(some_column)
  WHERE some_column IS NULL;

CREATE INDEX IAmTheRule ON dbo.table(some_column)
  WHERE some_column IS NOT NULL;

次に、次を使用して同様の方法でカウントを取得できます。

SELECT SUM(p.rows) FROM sys.partitions AS p
  INNER JOIN sys.tables AS t
  ON p.[object_id] = t.[object_id]
  INNER JOIN sys.schemas AS s
  ON s.[schema_id] = t.[schema_id]
  INNER JOIN sys.indexes AS i
  ON p.index_id = i.index_id
  WHERE t.name = N'myTable'
  AND s.name = N'dbo'
  AND i.name = N'IAmTheException' -- or N'IAmTheRule'
  AND p.index_id IN (0,1);

反対のことを知りたい場合は、上記の最初のクエリから減算するだけです。

于 2012-09-18T15:23:50.487 に答える
12

(「大量のデータ」とはどのくらいの大きさですか? - 最初にこれをコメントする必要がありましたが、以下の exec が既にあなたを助けているかもしれません)

私の開発マシンで 15 秒で 2 億行と COUNT(*) を持つ静的 (他の誰も読み取り/書き込み/更新に煩わされないので、競合は問題になりません) テーブルでクエリを実行すると (オラクル)。純粋なデータ量を考慮すると、これはまだかなり高速です(少なくとも私にとっては)

NOLOCKはオプションではないと言ったので、検討することができます

exec sp_spaceused 'myTable'

同じように。

しかし、これはNOLOCKとほぼ同じようにピン留めします(競合を無視+削除/更新afaik)

于 2012-09-18T15:09:40.233 に答える
4

私は 10 年以上にわたって SSMS を使用してきましたが、この回答のおかげで、この情報を迅速かつ簡単に提供できることがわかったのはつい最近のことです。

  1. データベース ツリー (オブジェクト エクスプローラー) から "Tables" フォルダーを選択します。
  2. F7 キーを押すか、[表示] > [オブジェクト エクスプローラーの詳細] を選択して、[オブジェクト エクスプローラーの詳細] ビューを開きます。
  3. このビューでは、列ヘッダーを右クリックして、使用されているテーブル スペース、使用されているインデックス スペース、行数など、表示する列を選択できます。 ここに画像の説明を入力

Azure SQLデータベースでのこれのサポートはせいぜい少しむらがあるように見えることに注意してください-私の推測では、SSMSからのクエリがタイムアウトしているため、更新ごとに少数のテーブルしか返されませんが、強調表示されたテーブルは常に返されるようです.

于 2019-05-16T06:11:01.720 に答える
2

Countは、テーブルスキャンまたはインデックススキャンのいずれかを実行します。したがって、行数が多い場合は遅くなります。この操作を頻繁に行う場合、最良の方法は、カウントレコードを別のテーブルに保持することです。

ただし、それを望まない場合は、ダミーのインデックス(クエリでは使用されません)を作成し、次のようにアイテムの数をクエリできます。

select 
    row_count
from sys.dm_db_partition_stats as p
inner join sys.indexes as i 
  on p.index_id = i.index_id
  and p.object_id = i.object_id
where   i.name = 'your index'

このインデックス(使用されない場合)は他の操作中にロックされないため、新しいインデックスを作成することをお勧めします。

Aaron Bertrandが言ったように、クエリを維持することは、既存のクエリを使用するよりもコストがかかる可能性があります。したがって、選択はあなた次第です。

于 2012-09-18T15:25:01.430 に答える