2010-05-21 76 views
1

我正在寻找将数据插入MS SQL数据库的性能非常高的可能性。数据是具有关系的对象(相对较大)的构造。出于安全原因,我想使用存储过程而不是直接表访问。MS SQL - 使用存储过程插入高性能数据

可以说我有这样的结构:

  • 文献
    • 元数据
      • 用户
      • 设备
    • 内容
      • ContentItem [0]
        • 子项[0]
        • 子项[1]
        • 子项[2]
      • ContentItem [1]
        • ...
      • ContentItem [2]
        • ...

现在我想建立一个大的查询,做这样服用点(只是伪代码):

EXEC @DeviceID = CreateDevice ...; 
EXEC @UserID = CreateUser ...; 
EXEC @DocID = CreateDocument @DeviceID, @UserID, ...; 

EXEC @ItemID = CreateItem @DocID, ... 
EXEC CreateSubItem @ItemID, ... 
EXEC CreateSubItem @ItemID, ... 
EXEC CreateSubItem @ItemID, ... 
... 

但这是性能的最佳解决方案吗?如果不是,那会更好吗? 将它拆分成更多querys?将所有数据提供给一个大的存储过程以减少查询的大小?任何其他表现线索?我也想过给一个存储过程多个项目,但我不认为它有可能给存储过程非静态数量的项目。由于'INSERT INTO A VALUES(B,C),(C,D),(E,F)比3个单个插入物更高效,所以我认为我可以在这里获得一些性能。

感谢您的任何提示, 商标

回答

1

一个存储过程尽可能:

INSERT INTO MyTable(field1,field2) 
SELECT "firstValue", "secondValue" 
UNION ALL 
SELECT "anotherFirstValue", "anotherSecondValue" 
UNION ALL 

如果你不能确定你能有多少项目,你要插入构造SQL查询在存储过程中,然后执行它。这里有一个程序,我写取组的CSV列表和添加他们的关系到用户的实体:

ALTER PROCEDURE [dbo].[UpdateUserADGroups] 
@username varchar(100), 
@groups varchar(5000) 
AS 
BEGIN 
DECLARE @pos int, 
@previous_pos int, 
@value varchar(50), 
@sql varchar(8000) 

SET @pos = 1 
SET @previous_pos = 0 
SET @sql = 'INSERT INTO UserADGroups(UserID, RoleName)' 

DECLARE @userID int 
SET @userID = (SELECT TOP 1 UserID FROM Users WHERE Username = @username) 

WHILE @pos > 0 
BEGIN 
SET @pos = CHARINDEX(',',@groups,@previous_pos+1) 
IF @pos > 0 
BEGIN 
SET @value = SUBSTRING(@groups,@previous_pos+1,@[email protected]_pos-1) 
SET @sql = @sql + 'SELECT ' + cast(@userID as char(5)) + ',''' + @value + ''' UNION ALL ' 
SET @previous_pos = @pos 
END 
END 

IF @previous_pos < LEN(@groups) 
BEGIN 
    SET @value = SUBSTRING(@groups,@previous_pos+1,LEN(@groups)) 
    SET @sql = @sql + 'SELECT ' + cast(@userID as char(5)) + ',''' + @value + '''' 
END 
print @sql 
exec (@sql) 

END 

这远远不是单个的INSERT更快。

此外,确保您只是主键上的单个聚集索引,更多索引会减慢INSERT,因为它们需要更新。

但是,您的数据集越复杂,您可以执行上述操作的可能性就越小,因此您只需做出逻辑折衷。实际上我最终调用了大约8000次的上述例程。

+0

你真的确定,构建查询比单个插入(制定基准)更快吗?我认为SQL服务器将无法使用缓存的执行计划进行即时生成的查询。但我会试一试。 有关IDS问题的任何想法?我认为生成所有父元素,然后生成所有子元素会更高效。但是如何在父元素中设置子元素的外键呢? – Marks 2010-05-21 09:59:22

+0

唯一可以告诉的方式是配置文件,我发现它使我的整个程序更快(不记得时间)。我不知道它是否会缓存执行计划,但它并不需要,因为它会非常基础。我的例子只能工作一层嵌套(一个记录与许多基本的孩子),也许看看序列化和解析你的项目从XML - http://weblogs.asp.net/jgalloway/archive/2007/02/ 16/passing-lists-to-sql-server-2005-with-xml-parameters.aspx – 2010-05-21 10:29:11

+0

我用我的一个CreateUser SP做了一些分析。 (...),(...),... * 1000个行(INSERT INTO Users(...))... 1000个行情况1:第一次:220ms,重复:〜220ms 情况2:第一次:2960ms,重复:~20ms 即使不创建INSERT INTO实时,由于提交的用户数量不同,插入缓存的执行计划的另一数量的用户被修复。 我会寻找一个Xml解决方案,并希望得到更好的结果。但是,谢谢。 – Marks 2010-05-21 11:32:25