我在我的 SQL Server 2005 数据库中创建了一个表,并用汇总和计算值填充它。目的是避免在每次调用数据库时进行大量连接和分组。我希望此表每小时刷新一次,但我不确定在网站负载时执行此操作的最佳方法。如果我删除每条记录并在一个事务中重新填充表,那会成功还是会出现死锁和其他潜伏的麻烦?
4 回答
我在几个项目中这样做的方式是在不同的模式中使用表的两个副本。所以像:
CREATE SCHEMA fake WITH AUTHORIZATION dbo;
CREATE SCHEMA standby WITH AUTHORIZATION dbo;
GO
CREATE TABLE dbo.mySummary(<...columns...>);
CREATE TABLE fake.mySummary(<...columns...>);
GO
现在创建一个截断并重新填充假表的存储过程,然后在事务中在模式之间移动对象。
CREATE PROCEDURE dbo.SwapInSummary
AS
BEGIN
SET NOCOUNT ON;
TRUNCATE TABLE fake.mySummary;
INSERT fake.mySummary(<...columns...>)
SELECT <expensive query>;
BEGIN TRANSACTION;
ALTER SCHEMA standby TRANSFER dbo.mySummary;
ALTER SCHEMA dbo TRANSFER fake.mySummary;
ALTER SCHEMA fake TRANSFER standby.mySummary;
COMMIT TRANSACTION;
END
GO
这可能是您可以让用户等待新数据刷新并且不会在读取过程中中断他们的最短时间。(与 NOLOCK 相关的许多问题使其成为不太理想的替代方案,尽管不可否认,它很容易编码。)为了简洁/清晰,我省略了错误处理等,我还应该指出,如果你使用同步数据库的脚本,确保在两个表上命名约束、索引等相同,否则一半时间会不同步。在程序结束时,您可以截断新的 fake.MySummary 表,但如果您有空间,我喜欢将数据留在那里,以便始终与以前的版本进行比较。
在 SQL Server 2005 之前,我在事务中使用 sp_rename 来完成完全相同的事情,但是由于我在工作中这样做,我很高兴切换到模式,因为当我这样做时,来自 sp_rename 的不可抑制警告停止填充起来我的 SQL Server 代理历史日志。
您还可以根据负载的重量创建索引视图,这可能是一个不错的选择
这取决于数据库中的关系以及针对它运行的查询。
如果它是一个可以容忍陈旧数据的汇总表,则可以使用查询来填充它,这些查询使用 NOLOCK 连接提示执行不带锁的 SELECT。注意:只有在您确定后果时才应使用 NOLOCK 提示。
通常有重新调整索引的空间,以减少负载。
我决定在@temp 表变量中建立数据。然后我会将汇总 ID 复制到它们匹配的临时表中。最后,我将基于@temp 表在汇总表中添加、更新和删除行。