基于集的批量化数据批量导入到规范化的SQL Server 2014数据库表中

时间:2016-01-22 11:21:50

标签: sql-server tsql sql-server-2014

以下简化模型适用于批量/基于插入#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

这可以用几百万条记录吗?

我想还可以降低日志记录级别?

1 个答案:

答案 0 :(得分:1)

  1. 我可以将上面的内容包装在一个事务(?)中,只有在整个批量导入完成后才能使#Things可用吗?像这样:
  2. BEGIN TRANSACTION X
     -- insert into all normalised tables
    COMMIT TRANSACTION X
    

    答案是肯定的。来自Documentation on Transactions

      

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

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

      

    原子性:确保工作单位内的所有操作都成功完成;否则,事务在失败时中止,之前的操作将回滚到以前的状态。

         

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

         

    隔离:使交易能够独立运作并相互透明。

         

    持久性:确保在系统出现故障时,已提交事务的结果或效果仍然存在。

    1. 这会有几百万个条目吗?
    2. 再次,是的。条目数量无关紧要。用我自己的话来说:

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

      • 隔离:除非提交,否则其他交易不会看到其他交易的操作。

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

        

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

      这是在性能和​​一致性之间取得平衡的权衡级别。理想情况下,您会想要所有内容SERIALIZABLE(请参阅文档,复制/粘贴时间太长)。此隔离级别将性能( - )换成一致性(+)。在很多情况下,READ COMMITTED隔离级别已经足够好了,但是您应该知道它是如何工作的,并将其与您的事务应该如何相对于其他事务的完成工作。

      另请注意,事务将锁定数据库对象(行,表,模式...),如果要读取或修改这些对象(取决于锁的类型),其他事务将阻塞。因此,最好将交易中的操作量保持在较低水平。但有时候,交易只会做很多事情而且不能分解。