19

我想以最好的方式换到桌子。
我有一个 IpToCountry 表,我每周根据我导入的外部 CSV 文件创建一个新表。

我发现进行切换的最快方法是执行以下操作:

sp_rename IpToCountry IpToCountryOld
go
sp_rename IpToCountryNew IpToCountry
go

这样做的问题是表可能仍然在两者之间被访问。
如何在 SQL 中解决这个问题?
在考虑使用 sp_getapplock 和 sp_releaseapplock,但我想尽可能快地保持从表中读取的功能。

4

6 回答 6

17

假设您无法更新/插入现有表,为什么不使用视图包装对表的所有访问?

例如,您可能最初将数据存储在名为IpToCountry20090303的表中,您的视图将如下所示:

CREATE VIEW IpToCountry
AS
SELECT * FROM IpToCountry20090303

当新数据进来时,您可以创建并填充IpToCountry20090310表。填充表格后,只需更新您的视图:

ALTER VIEW IpToCountry
AS
SELECT * FROM IpToCountry20090310

切换将是完全原子的,不需要任何显式锁定或事务。视图更新后,您可以简单地删除旧表(如果您愿意,也可以保留它)。

于 2009-03-03T11:36:40.213 回答
3

我在让分区功能大规模工作时遇到了问题。CREATE 和 DROP PARTITION 是阻塞操作,您对阻塞几乎没有控制权,如果它无法获得锁,它将以严重级别 16 失败并终止您的连接——如果不重新建立,您将无法捕获并重试连接。但它可能对你有用。此外,需要 MSS 企业版,您不能使用 SE——对于一些规模较小或成本较高的商店来说可能太多了。

我还发现视图 redef 会在 sys 表和对象上以大规模(= 事务量 + 不断插入的数据的绝对量)阻塞 sys 表和对象,因此这些操作可能会在诸如重新索引和 DTCC 之类的事情上死锁——在一种情况下,特别是 SSMS 中的用户(所有事物)试图在对象资源管理器中浏览视图(有人需要告诉那些人有关 READPAST 的信息)。同样,您的里程可能会有所不同。

相比之下, sp_rename 在规模上对我来说效果很好:它使您可以控制锁定及其范围。要在交换之前解决阻塞问题,请尝试如下所示。从表面上看,这似乎在大批量时具有相同的规模问题......但我在实践中没有看到它。所以,为我工作......但同样,每个人的需求和经历都是不同的。

DECLARE @dummylock bit 
BEGIN TRANSACTION 
BEGIN TRY
   -- necessary to obtain exclusive lock on the table prior to swapping
   SELECT @dummylock = 1 WHERE EXISTS (SELECT 1 FROM A WITH (TABLOCKX))
   -- may or may not be necessary in your case
   SELECT @dummylock = 1 WHERE EXISTS (SELECT 1 FROM B WITH (TABLOCKX))
   exec sp_rename 'A', 'TEMP'
   exec sp_rename 'B', 'A'
   exec sp_rename 'TEMP', 'B'
   COMMIT TRANSACTION
END TRY
BEGIN CATCH
   -- other error handling here if needed
   ROLLBACK TRANSACTION 
END CATCH
于 2011-03-11T15:53:42.240 回答
1

另一种实现您希望实现的方法是使用表分区,这是一种在 SQL Server 企业版中可用的技术。

表名可以保持不变。表导入完成后,您只需简单地切换包含旧数据的分区并切换到新分区。

以下白皮书包含您入门所需的所有信息。

http://msdn.microsoft.com/en-us/library/ms345146.aspx

干杯,约翰

于 2009-03-03T12:34:22.100 回答
0

IpToCountryOld 会发生什么?你把它扔掉吗?在这种情况下,为什么不截断 IpToCountry 并导入我的新数据。

如果您需要保留数据,如何将加载日期存储在表上并将“当前”加载日期存储在某个地方以在 WHERE 子句中使用?然后在数据成功加载时切换当前日期。

你没有说你使用的是哪个数据库,所以我不知道它有多大用处,但是你有任何引用该表的存储过程吗?请注意,在某些平台上,SP 是使用对不会随重命名而更改的表的内部引用进行编译的,因此存在 SP 在不重新编译的情况下不会获取新数据的风险。视图和存储的解析查询也是如此。

于 2009-03-03T09:57:33.383 回答
0

你不能在下班时间不导入一张桌子吗?

或者为什么不只是进行数据更新,即更新现有记录并在循环导入数据时逐条记录添加任何新记录。这将使表保持活动状态并减少添加和删除完整表的整体影响。

被导入的数据是什么结构,表格设计,格式,PK等?由此我们或许可以给你一个更好的答案。

于 2009-03-03T10:31:29.527 回答
0

刚刚在一个临时表上遇到了类似的问题,该表在使用适当的锁进行缩放时遇到了问题。

在引用您的表的任何地方,您都可以调用一个存储过程来询问表名。

存储过程可以根据提供的参数选择创建新表或返回旧表。

于 2013-04-13T19:47:37.693 回答