2016-01-22 50 views
0

以下简化实体模型,工作正常散装/组基于插入去归一化数据#BulkData(改进建议表示欢迎):Set-based的批量导入

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

为什么重要的是它在顺序查询之前是“可访问的”? –

+0

将事情看作“聚合根”。如果在#ThingsToCategories填充之前检索到某个东西,则客户端看到的任何内容都可能不代表现实(希望这是有道理的)。 – cs0815

+0

但是表#只能在运行查询的会话中访问,并且它会按顺序运行? –

回答

1
  1. 我可以在事务(?)中包装上述内容,以便在整个批量导入完成时使#Things可用吗?像这样:

BEGIN TRANSACTION X 
-- insert into all normalised tables 
COMMIT TRANSACTION X 

答案是肯定的。从Documentation on Transactions

交易是一个单一的工作单位。如果事务成功,则在事务期间进行的所有数据修改都将被提交并成为数据库的永久部分。如果事务遇到错误并且必须被取消或回滚,则所有数据修改都将被删除。

事务具有以下四种标准属性,通常由首字母缩略词ACID引用。引用自tutorialspoint.com上的以下链接SQL Transactions

原子性:确保工作单元内的所有操作都已成功完成;否则,事务将在故障点中止,并且以前的操作将回滚到以前的状态。

一致性:确保数据库在成功提交事务后正确更改状态。

隔离:使事务能够彼此独立且透明地进行操作。

耐久性:确保承诺事务的结果或效果在系统发生故障时仍然存在。


  • 将与数百万条目这项工作?

  • 再次,是的。条目数量无关紧要。在我自己的话这个时间:

    • 原子性:如果交易成功,交易中的所有操作都将尽快处理完成后,即在事务提交时生效。如果事务中至少有一个操作失败,所有操作都会回滚(换句话说,没有任何操作)。 交易内的操作量无关紧要。

    • 隔离:其他交易将不会看到其他交易的操作,除非他们承诺。

    但是有不同的Transaction Isolation Levels。 SQL Server的默认值是READ COMMITTED

    指定语句不能读取已被修改但未被其他事务提交的数据。 [...]

    这是性能和一致性之间平衡的权衡级别。理想情况下,您需要一切SERIALIZABLE(请参阅文档,复制/粘贴时间太长)。此隔离级别为了一致性(+)而交易性能( - )。在很多情况下,隔离级别已经足够好了,但您应该意识到它的工作原理,并将其与您的交易应该如何与其他交易的完成相关联。

    还要注意,一个事务会锁定数据库对象(行,表,模式等),并且如果他们想要读取或修改这些对象(取决于锁的类型),其他事务将会被阻塞。出于这个原因,最好保持交易量低。有时候,交易只是做了很多事情,而且不能分解。

    +0

    我知道什么是交易,但将这项工作与几百万条目? – cs0815

    +0

    @csetzkorn更新为新的问题 –

    +0

    非常感谢,我可能会在隔离级别上玩一下。 – cs0815