web-dev-qa-db-ja.com

SQL ServerのCOUNT(*)は一定時間の操作ですか?そうでない場合は、なぜですか?

私はこの議論を 別の投稿 で読んでおり、この質問は他の誰かによって提起されました。議論を読む前に、SQL Server(および他のDBMS)がメタデータ内のどこかで各テーブルの行のグローバルカウントを保持することを常に考えていましたが、議論はそうではないと言っているようです。どうして? Count(*)(フィルタリングなし)がこのような一般的な操作である場合、O(1)の場合は大幅に増加します。 COUNT(*)を考慮しなくても、テーブル内の行の総数はこのような基本的な情報です。なぜ彼らはそれを記録しないのですか?

さらに、それらを数えるためだけに行全体を「ロード」する必要があるのはなぜですか(リンクした投稿に示されているように)。インデックスやPKなどはそれらをカウントするのに十分ではありませんか?

36
dotNET

いいえ、COUNT(*)は一定時間の操作ではありません。 COUNT(*)は、現在のスキャン述語(つまり、WHERE句)に準拠する行の数を返す必要があります。これにより、単独でメタデータプロパティの戻りが無効になります。ただし、述語がない場合でも、COUNTは現在のトランザクション分離セマンティクスを満たさなければなりません。行数を返しますvisible(例:コミット済み)。したがって、COUNTは、SQL Serverで実際に行をスキャンしてカウントする必要があります。一部のシステムでは、 高速な「推定」カウント を返すことができます。

また、サイドコメントとして、 _sys.partitions_rowsに依存することは信頼できません。結局、このカウントが正確であることが保証される場合、 DBCC UPDATEUSAGE(...) WITH COUNT_ROWS は必要ありません。歴史的にこのカウンターが現実から離れるのを引き起こすいくつかのシナリオがあります(ほとんどログに記録された挿入のロールバック)、私が知っているすべては修正されていますが、それでも1)バグと2 )その他の、まだ発見されていないバグ。

さらに、それらを数えるためだけに行全体を「ロード」する必要があるのはなぜですか(リンクした投稿に示されているように)。インデックスやPKなどはそれらをカウントするのに十分ではありませんか?

これは100%真実ではありません。 「行全体をロード」しない少なくとも2つのシナリオがあります。

  • 狭い行ストアインデックスは、「インデックス」行のみをロードします。
  • 列ストアのデータは、関連する列セグメントのみをロードします

そして、私が上で言ったことのほとんどは、ヘカトンのテーブルには適用されません。

56
Remus Rusanu

行全体を「ロード」する必要があるのはなぜですか

しません。 SQL Serverは、クエリを満たすことができる最小のインデックスを使用する傾向があります。

Count(*)(フィルタリングなし)はこのような一般的な操作です

あなたはその有病率を過大評価していると思います。フィルター処理されたビューや、より複雑な結合操作のカウントに対して、1つのテーブルの行の総数を最後に気にしたことを思い出せません。

それは例外的にnarrow最適化であり、単一のスタイルのクエリのみにメリットがあります。

21