集計で合計を使用してパフォーマンスを向上させます
-
16-10-2019 - |
質問
これらの詳細の詳細と合計の2つの表があります。
詳細 (ゆっくりとした解決策):
select
OrderId = r.OrderId
, TotalQty = SUM(r.Quantity)
, TotalGrossConsid = SUM(r.Price * r.Quantity)
from dbo.Order r
group by r.OrderId
合計(高速ソリューション):
select
t.OrderId
, t.TotalQty
, t.TotalGrossConsid
, t.IsValid
from dbo.OrderTotal t
合計が無効になることがあります(一部のジョブは、合計の変更を再計算する必要がありますが、遅延します)。理解するにつれて、2番目のクエリはより速く、有効な合計の数は無効なものよりも多くなります。そのため、2番目のテーブル(合計)から有効な合計を返す合計クエリを探しており、最初のスロークエリを使用して動的に再計算された合計を返します。したがって、私の目標は到達します。すべての合計は有効であり、応答するまでの時間は完全な再計算よりも高速です。
これが私の試みです(ハイブリッドソリューション):
with fast_static(OrderId, TotalQty, TotalGrossConsid, IsValid)
as
(
select
t.OrderId
, t.TotalQty
, t.TotalGrossConsid
, t.IsValid
from dbo.OrderTotal t
)
, slow_dynamic(OrderId, TotalQty, TotalGrossConsid)
(
select
OrderId = r.OrderId
, TotalQty = SUM(r.Quantity)
, TotalGrossConsid = SUM(r.Price * r.Quantity)
from dbo.Order r
)
select
OrderId, TotalQty, TotalGrossConsid
from fast_static
where IsValid = 1
union all
select
OrderId, TotalQty, TotalGrossConsid
from slow_dynamic s
--inner join fast_static ff
--on ff.OrderId = s.OrderId
where --ff.Valid = 0 -- too slow!!!
s.OrderId in (select OrderId from fast_static f where f.Valid = 0)
高速ソリューションとハイブリッドソリューションを比較しました。32%から68%(相対クエリコスト)を得ました。コメントされたバリアントを見ることができれば、それは1%から99%に等しくなります(あまりにも悪い)。このクエリを改善することは可能ですか?
追加した
@GBN:
Valid = case when i.OrderId is null then 1 else 0 end
...
dbo.OrderTotal t left join dbo.InvalidOrders i
はい、合計を再計算する仕事があり、このプロセスはクエリリクエストに同期されていません。 InvalIdordersテーブルは、合計が無効であることを知るために記録を保存する小さなものです(再計算される)
解決
インデックス付きビューが最良の選択です。 SQL Server Editionに注意してください(ノーエクスパンドヒント 非植物版のために)そして準備ができています いくつかのデータベースオブジェクトを再作成します (SET ANSI_NULLS ON, SET QUOTED_IDENTIFIER ON
)クライアント側でインデックス付きビューの使用を開始します。
解決
なぜあなたがその場で集約できないのか、なぜそれがそんなに遅いのか理解できません。 「有効な」アイデアは、OrderTotalsまたはいくつかのビジネスプロセスの遅れに対処するための回避策ですか
これらのアイデアはどちらも、索引不良の回避策である無効な注文テーブルを破棄します。
- 提案1:
計算された列を作成します
ALTER TABLE dbo.Order ADD PriceXQuantity AS Price * Quantity PERSISTED
インデックスを追加します
CREATE INDEX IX_Totals ON dbo.Order (OrderID) INCLUDE Quantity, PriceXQuantity)
何が起こるか見てください
- 提案2:
インデックス付きビューを使用します
CREATE VIEW OrderTotals
WITH SCHEMABINDING
AS
select
OrderId = r.OrderId
, TotalQty = SUM(r.Quantity)
, TotalGrossConsid = SUM(r.Price * r.Quantity)
, COUNT_BIG(*) AS Dummy
from dbo.Order r
group by r.OrderId
GO
CREATE UNIQUE CLUSTERED INDEX IXCU_OrderTotals ON OrderTotals (OrderId9
GO
ここでも計算された列も使用できます
他のヒント
コストが高すぎない場合は、移動を検討することができます IsValid
にフラグ Detail
テーブルとインデックスを作成しますか?これにより、トランザクションが遅くなりますが、(おそらく)大きいようにクエリパフォーマンスを改善します Detail
テーブルは1つのビッグでアクセスされます range scan