以下简化模型适用于批量/基于插入#BulkData
中的非规范化数据(欢迎改进建议):
IF OBJECT_ID('tempdb..#Things') IS NOT NULL
DROP TABLE #Things
IF OBJECT_ID('tempdb..#Categories') IS NOT NULL
DROP TABLE #Categories
IF OBJECT_ID('tempdb..#ThingsToCategories') IS NOT NULL
DROP TABLE #ThingsToCategories
IF OBJECT_ID('tempdb..#BulkData') IS NOT NULL
DROP TABLE #BulkData
CREATE TABLE #Things
(
ThingId INT IDENTITY(1,1) PRIMARY KEY,
ThingName NVARCHAR(255)
)
CREATE TABLE #Categories
(
CategoryId INT IDENTITY(1,1) PRIMARY KEY,
CategoryName NVARCHAR(255)
)
CREATE TABLE #ThingsToCategories
(
ThingId INT,
CategoryId INT
)
CREATE TABLE #BulkData
(
ThingName NVARCHAR(255),
CategoryName NVARCHAR(255)
)
-- the following would be done from a flat file via a bulk import
INSERT INTO #BulkData
SELECT N'Thing1', N'Category1'
UNION
SELECT N'Thing2', N'Category1'
UNION
SELECT N'Thing3', N'Category2'
INSERT INTO #Categories
SELECT DISTINCT CategoryName
FROM #BulkData
WHERE CategoryName NOT IN (SELECT DISTINCT CategoryName
FROM #Categories)
INSERT INTO #Things
SELECT DISTINCT ThingName
FROM #BulkData
WHERE ThingName NOT IN (SELECT DISTINCT ThingName FROM #Things)
INSERT INTO #ThingsToCategories
SELECT ThingId, CategoryId
FROM #BulkData
INNER JOIN #Things ON #BulkData.ThingName = #Things.ThingName
INNER JOIN #Categories ON #BulkData.CategoryName = #Categories.CategoryName
SELECT * FROM #Categories
SELECT * FROM #Things
SELECT * FROM #ThingsToCategories
我对上述问题的一个问题是,在将数据插入#Things
之前,#ThingsToCategories
中的数据是可访问的。
我可以将上述内容包装在一个事务(?)中,以便只在整个批量导入完成后使#Things可用吗?
像这样:
BEGIN TRANSACTION X
-- insert into all normalised tables
COMMIT TRANSACTION X
这可以用几百万条记录吗?
我想还可以降低日志记录级别?
答案 0 :(得分:1)
BEGIN TRANSACTION X
-- insert into all normalised tables
COMMIT TRANSACTION X
答案是肯定的。来自Documentation on Transactions:
交易是一个单一的工作单位。如果事务成功,则在事务期间进行的所有数据修改都将被提交并成为数据库的永久部分。如果事务遇到错误并且必须取消或回滚,则所有数据修改都将被删除。
交易具有以下四种标准属性,通常由首字母缩略词ACID引用。引自SQL Transactions上的tutorialspoint.com上的以下链接:
原子性:确保工作单位内的所有操作都成功完成;否则,事务在失败时中止,之前的操作将回滚到以前的状态。
一致性:确保数据库在成功提交的事务时正确更改状态。
隔离:使交易能够独立运作并相互透明。
持久性:确保在系统出现故障时,已提交事务的结果或效果仍然存在。
再次,是的。条目数量无关紧要。用我自己的话来说:
原子性:如果事务成功,事务中的所有操作将在事务完成后立即生效,即在事务提交时生效。如果事务中至少有一个操作失败,则回滚所有操作(换句话说,没有任何操作)。 交易中的操作数量无关紧要。
隔离:除非提交,否则其他交易不会看到其他交易的操作。
但有Transaction Isolation Levels不同。 SQL Server的默认值为READ COMMITTED
:
指定语句无法读取已修改但未由其他事务提交的数据。 [...]
这是在性能和一致性之间取得平衡的权衡级别。理想情况下,您会想要所有内容SERIALIZABLE
(请参阅文档,复制/粘贴时间太长)。此隔离级别将性能( - )换成一致性(+)。在很多情况下,READ COMMITTED
隔离级别已经足够好了,但是您应该知道它是如何工作的,并将其与您的事务应该如何相对于其他事务的完成工作。
另请注意,事务将锁定数据库对象(行,表,模式...),如果要读取或修改这些对象(取决于锁的类型),其他事务将阻塞。因此,最好将交易中的操作量保持在较低水平。但有时候,交易只会做很多事情而且不能分解。