Kyl*_*Mit 5 sql-server aggregate cache sql-server-2012
我们有一个InventoryActivity
表,用于保存项目数量的交易变化:
CREATE TABLE dbo.InventoryActivity(
InventoryActivity_uid int IDENTITY(1,1) NOT NULL PRIMARY KEY,
Organization_uid int NOT NULL,
MasterInventory_uid int NOT NULL,
AdjustmentType_cd varchar(20) NULL,
AdjustmentReason_cd varchar(20) NULL,
Quantity int NULL
)
Run Code Online (Sandbox Code Playgroud)
我们想要一个InventorySummary
应该聚合到每个的当前数量。汇总计数应该始终可以从交易记录的总和中推导出来,但是我们有几种不同的方法来计算汇总计数:
哪些性能考虑因素应该使天平有利于特定策略?
存在哪些最佳实践? *(我知道最佳实践接近于讨论,但我想知道哪些考虑会有助于做出决定)
存储过程
最简单的选择是每次都执行新鲜的 SUM 操作。但不涉及缓存,随着时间的推移可能会导致性能问题。
CREATE PROCEDURE dbo.GetInventorySummary
AS
SELECT Organization_uid,
MasterInventory_uid,
SUM(Quantity) AS Quantity
FROM dbo.InventoryActivity
GROUP BY Organization_uid, MasterInventory_uid
Run Code Online (Sandbox Code Playgroud)单独的表
我们可以创建一个表来存储当前数量。好的一面是获取这些数据是微不足道的。缺点是我们每次写入 InventoryActivity 表时都必须手动维护它并保持记录同步。
CREATE TABLE dbo.InventorySummary(
Organization_uid int NOT NULL,
MasterInventory_uid int NOT NULL,
Quantity int NOT NULL,
PRIMARY KEY (Organization_uid, MasterInventory_uid)
)
Run Code Online (Sandbox Code Playgroud)
触发器可以帮助减轻一些维护。
CREATE TRIGGER dbo.InventoryActivity_I
ON dbo.InventoryActivity
AFTER INSERT
AS
CREATE TABLE #InsertSummaryTemp
(
Organization_uid int,
MasterInventory_uid int,
Quantity int
)
INSERT INTO #InsertSummaryTemp
SELECT Organization_uid,
MasterInventory_uid,
SUM(Quantity) AS Quantity
FROM INSERTED
GROUP BY Organization_uid, MasterInventory_uid
-- UPDATE EXISTING RECORDS
UPDATE InventorySummary
SET Quantity = s.Quantity + i.Quantity
FROM InventorySummary s
JOIN #InsertSummaryTemp i ON s.Organization_uid = i.Organization_uid AND
s.MasterInventory_uid = i.MasterInventory_uid
-- INSERT NEW RECORDS
INSERT INTO InventorySummary
(Organization_uid, MasterInventory_uid, Quantity)
SELECT i.Organization_uid, i.MasterInventory_uid, i.Quantity
FROM #InsertSummaryTemp i
LEFT JOIN InventorySummary s ON i.Organization_uid = s.Organization_uid AND
i.MasterInventory_uid = s.MasterInventory_uid
WHERE s.MasterInventory_uid IS NULL
Run Code Online (Sandbox Code Playgroud)索引视图
借用this和this我们可以创建一个Indexed View
. 这降低了与选项 2 相关的维护成本。但是,我们仍然在汇总整个历史记录中的所有记录,因此存在性能问题。与从表中简单读取相反。
CREATE VIEW dbo.InventorySummaryView
WITH SCHEMABINDING
AS
SELECT
Organization_uid,
MasterInventory_uid,
SUM(Quantity) AS Quantity,
COUNT_BIG(*) AS Count
FROM dbo.InventoryActivity
GROUP BY Organization_uid, MasterInventory_uid
GO
CREATE UNIQUE CLUSTERED INDEX PK_InventorySummaryView ON dbo.InventorySummaryView
(
Organization_uid,
MasterInventory_uid
)
Run Code Online (Sandbox Code Playgroud)哪些性能考虑因素应该使天平有利于特定的策略?
本质上,与任何形式的缓存一样,这些策略允许以牺牲写入和磁盘空间为代价来提高读取性能。
因此,您应该考虑以下事项:
第一个策略是基线。您无需复制数据,写入速度尽可能快。
最后一个策略(索引视图)会立即减慢写入速度(当写入发生时),但聚合金额始终是最新的。
具有显式汇总表的第二种策略使您可以更好地控制何时执行聚合。您可以延迟聚合并在服务器负载较低时执行聚合。如果您积累一堆待处理的更改来计算摘要并批量执行这些计算,则可能比在源数据的每次更改后更新摘要更有效。
另一方面,在更新期间维护索引视图的引擎应该足够智能,可以通过仅将更改应用于摘要来更新摘要,而无需每次都读取整个表。例如,如果您只更新 10M 表中的 2 行,那么为了计算新值,SUM(Quantity)
引擎可以减去两个旧值Quantity
并添加两个新值。我手头没有权威的来源来确认该引擎确实是这样工作的,但通过测量一个大表上的一些测试语句的读写量应该相当容易测试和验证。
这导致需要考虑另一件事:
SUM
高效地保持最新状态很容易,但对于MIN
.