MS SQL - высокопроизводительная вставка данных с помощью хранимых процедур - PullRequest
1 голос
/ 21 мая 2010

Я ищу очень высокую производительность для вставки данных в базу данных MS SQL. Данные представляют собой (относительно большую) конструкцию объектов с отношениями. Из соображений безопасности я хочу использовать хранимые процедуры вместо прямого доступа к таблице.

Допустим, у меня есть такая структура:

  • Документ
    • MetaData
      • Пользователь
      • Устройство
    • Содержание
      • ContentItem [0]
        • подпозиция [0]
        • подэлемент [2]
      • ContentItem [1]
        • ...
      • ...

Сейчас я думаю о том, чтобы создать один большой запрос и выполнить что-то вроде этого (просто псевдокод):

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

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

Но это лучшее решение для производительности? Если нет, то что будет лучше? Разделить это на несколько запросов? Передать все данные одной большой хранимой процедуре, чтобы уменьшить размер запроса? Любая другая подсказка производительности?

Я также думал о предоставлении нескольких элементов одной хранимой процедуре, но я не думаю, что возможно дать нестатическое количество элементов для хранимой процедуры. Поскольку 'INSERT INTO A VALUES (B, C), (C, D), (E, F) более производительны, чем 3 отдельных вставки, я подумал, что смогу добиться некоторой производительности здесь.

Спасибо за любые подсказки, Marks

1 Ответ

1 голос
/ 21 мая 2010

Одна хранимая процедура, насколько это возможно:

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

Если вы не уверены, сколько элементов вы вставляете, вы можете создать SQL-запрос в sproc, а затем выполнить его.Вот процедура, которую я написал, чтобы взять список групп 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,@pos-@previous_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

Это намного быстрее, чем отдельные ВСТАВКИ.

Кроме того, убедитесь, что вы простоодин кластеризованный индекс на первичном ключе, большее количество индексов замедлит вставку, поскольку им потребуется обновить.

Однако, чем сложнее ваш набор данных, тем меньше вероятность, что вы сможетесделайте выше, так что вам просто придется идти на логические компромиссы.Я на самом деле заканчиваю вызывать вышеупомянутую процедуру около 8000 раз.

...