Count(*)vsキープカウンターを選択します
-
29-09-2019 - |
質問
インデックスが導入されており、絶対的な総計が必要であると仮定すると(1つか2つ離れていても大丈夫です)、使用しても大丈夫です。
オプションa
select count(*)
from Table
where Property = @Property
vs
オプションb
update PropertyCounters
SET PropertyCount = PropertyCount + 1
where Property = @Property
その後:
select PropertyCount
from PropertyCounters
where Property = @Property
テーブルが数千/数百万のレコードに成長するにつれて、Select Count(*)を実行することで、どのくらいのパフォーマンスの劣化が合理的に期待できますか?
解決
実際のデータに加えて個別のカウント列を維持することは、非正規化です。パフォーマンスのためにそれをする必要があるかもしれない理由がありますが、本当に必要になるまでそこに行くべきではありません。これにより、コードがより複雑になり、矛盾が忍び寄る可能性が高くなります。
クエリが本当にあるだけの単純なケースのために SELECT COUNT(property) FROM table WHERE property=...
, 、非正規化する理由はありません。にインデックスを追加することで、それを迅速に作成できます property
桁。
他のヒント
プラットフォームを指定しませんでしたが、@VariablesにT-SQL構文を使用するため、SQL Serverプラットフォームの特定の回答をベンチャーします。
count(*)
, 、または厳密に言えば count_big(*)
, 、インデックス付きビューで使用できる式です。 インデックス付きビューの設計.
create view vwCounts
with schembinding
as select Property, count_big(*) as Count
from dbo.Table
group by Property;
create unique clustered index cdxCounts on vwCounts(Property);
select Count
from vwCount with (noexpand)
where Property = @property;
エンタープライズエディションでは、オプティマイザーは元のクエリにインデックス付きビューを使用します。
select count_big(*)
from Table
where Property = @property;
結局、あなたはあなたのケーキを手に入れてそれを食べます:プロパティはすでにエンジンによって無料で集約され、維持されています。価格は、更新がインデックス付きビューを維持する必要があるということです(彼らは いいえ ただし、集約カウントを再計算します)と集約により、競合のホットスポットが作成されます(テーブル上の個別の行のロックは、インデックスビューの同じカウント(*)更新に対して競合します)。
絶対的な精度を必要としないと言う場合、オプションBは奇妙なアプローチです。オプションAが重すぎて(インデックスを追加した後でも)場合、メモリまたは別のテーブル(PropertyCounters)にオプションAの出力をキャッシュし、定期的に更新できます。
これは、一般的なSQL用語で答えることができるものではありません。インデックスなどに関する通常の警告などとは別に、クエリに影響を与えることについては、プラットフォーム間でかなり異なるものもあります。
SQL ServerよりもSQL ServerよりもSQL Serverからのパフォーマンスの向上に賭けます。後者のアプローチは、SQL ServerではなくPostgresでより早くアプローチすると考えます。ただし、基準を一致させるのに適した部分インデックスセットを使用すると、PostgresがSQL Serverを打ち負かすことに賭けます。それはちょうど私が小さな賞金を賭けていることですが、いずれにせよ、私はそれについて実際に考える必要があるかどうかをテストします。
後者のアプローチに行く場合は、トリガーなどで実施して、不正確になることができないようにします。
SQL Serverでは、完全に正確なカウントを必要としない場合は、カタログビューを検査することもできます。これははるかに簡単です - あなたは自分自身をカウントする必要はありません - そして、それはシステムに対する課税がはるかに少ないです。結局のところ、テーブル内のすべての行をカウントする必要がある場合は、そのテーブルを何らかの形でスキャンする必要があります。
ここでこのSQLステートメントを使用すると、SQL Serverが保持しているように、データベース内のすべてのテーブルとその行数が表示されます。
SELECT
t.NAME AS TableName,
SUM(p.rows) AS RowCounts
FROM
sys.tables t
INNER JOIN
sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN
sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
WHERE
t.NAME NOT LIKE 'dt%' AND
i.OBJECT_ID > 255 AND
i.index_id <= 1
GROUP BY
t.NAME, i.object_id, i.index_id, i.name
ORDER BY
OBJECT_NAME(i.object_id)
通常、それらの数値が正確にどのようにあるかについてのドキュメントを見つけることができませんでしたが、私自身の経験から、通常はその場にいます(いくつかのバルクロードなどをしていない限り - しかし、その場合、あなたはしません。 Tテーブルを絶えずスキャンして正確なカウントを取得したい)