Код C # и производительность SQL Server - PullRequest
1 голос
/ 12 октября 2010

У меня есть база данных SQL Server, сконструированная так:

TableParameter
  Id    (int, PRIMARY KEY, IDENTITY)
  Name1 (string)
  Name2 (string, can be null)
  Name3 (string, can be null)
  Name4 (string, can be null)

TableValue
  Iteration         (int)
  IdTableParameter  (int, FOREIGN KEY)
  Type              (string)
  Value             (decimal)

Итак, как вы только что поняли, TableValue связан с TableParameter.TableParameter похоже на многомерный словарь.

TableParameter должно иметь много строк (более 300 000 строк)

Из моей клиентской программы на c # я должен заполнить эту базу данныхпосле каждой Compute() функции:

for (int iteration = 0; iteration < 5000; iteration++)
{
    Compute();
    FillResultsInDatabase();
}

В методе FillResultsInDatabase() я должен:

  1. Проверить, существует ли метка моего параметра в TableParameter.Если он не существует, я должен вставить новый.
  2. Я должен вставить значение в TableValue

Шаг 1 занимает много времени!Я загружаю всю таблицу TableParameter в свойство IEnumerable, а затем для каждого параметра я создаю

.FirstOfDefault( x => x.Name1 == item.Name1 &&
                      x.Name2 == item.Name2 &&
                      x.Name3 == item.Name3 &&
                      x.Name4 == item.Name4 );

, чтобы определить, существует ли она уже (и после получения идентификатора).

Производительность очень плохая, как это!

Я пытался сделать выбор с помощью слова WHERE, чтобы избежать загрузки каждой строки TableParameter, но производительность хуже!

Как я могу улучшить производительность шага 1?

Для шага 2 производительность по-прежнему плоха с классическим INSERT.Я собираюсь попробовать SqlBulkCopy.

Как мне улучшить производительность шага 2?

EDITED

Я пытался с процедурой хранения:

CREATE PROCEDURE GetIdParameter
    @Id     int OUTPUT,
    @Name1  nvarchar(50) = null,
    @Name2  nvarchar(50) = null,
    @Name3  nvarchar(50) = null
AS
SELECT TOP 1 @Id = Id FROM TableParameter
WHERE
TableParameter.Name1 = @Name1   
AND
(@Name2 IS NULL OR TableParameter.Name2= @Name2)
AND
(@Name3 IS NULL OR TableParameter.Name3 = @Name3)
GO

CREATE PROCEDURE CreateValue
    @Iteration int,
    @Type   nvarchar(50),
    @Value  decimal(32, 18),
    @Name1  nvarchar(50) = null,
    @Name2  nvarchar(50) = null,
    @Name3  nvarchar(50) = null
AS
DECLARE @IdParameter int
EXEC GetIdParameter @IdParameter OUTPUT, 
                    @Name1, @Name2, @Name3
IF @IdParameter IS NULL
BEGIN
    INSERT TablePArameter (Name1, Name2, Name3) 
                               VALUES
                              (@Name1, @Name2, @Name3)

    SELECT @IdParameter= SCOPE_IDENTITY()
END
  INSERT TableValue (Iteration, IdParamter, Type, Value) 
                              VALUES
                              (@Iteration, @IdParameter, @Type, @Value)
GO

У меня все еще та же производительность ... :-( (не приемлемо)

Ответы [ 4 ]

2 голосов
/ 12 октября 2010

Если я понимаю, что происходит, вы запрашиваете базу данных, чтобы увидеть, есть ли данные на шаге 1. Я бы использовал вызов db хранимой процедуры, которая вставляет данные, если их там нет.Так что просто вычислите результаты и передайте в sp.

Можете ли вы сначала вычислить результаты, а затем вставить в пакеты?

Принимает ли функция вычисления данные из базы данных?Если да, можете ли вы превратить операцию в операцию на основе набора и выполнить ее на самом сервере?Или может быть частью этого?

Помните, что сервер sql предназначен для операций с большим набором данных.

Редактирование: отображение комментариев Поскольку код медленно вставляется, и вы подозреваете, что это потому, чтовставка должна выполнить поиск до того, как она будет выполнена, я бы посоветовал вам разместить индексы SQL в столбцах, по которым вы ведете поиск, чтобы повысить скорость поиска.

Однако у меня есть другая идея.

Почему бы вам просто не вставить данные без чека, а затем, когда вы прочитаете данные, удалить дубликаты в этом запросе?

0 голосов
/ 12 октября 2010

самый быстрый способ (я знаю до сих пор) - это массовая вставка. но не только строки INSERT. попробуйте вставить + выбрать + объединение. это работает довольно быстро.

insert into myTable
select a1, b1, c1, ...
union select a2, b2, c2, ...
union select a3, b3, c3, ...
0 голосов
/ 12 октября 2010

Я должен признать, что я изо всех сил пытаюсь понять бизнес-процесс, который вы пытаетесь достичь здесь.

При первоначальном рассмотрении кажется, что вы выполняете сравнение данных на уровне своего приложения.Я бы посоветовал против этого и предложил бы, чтобы компонент Database Engine делал то, для чего он предназначен, для управления и реализации вашего доступа к данным.

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

Также следует учитывать:

  • Применение логики / правила вставки путем создания уникального ограничения для четырех столбцов имени.
  • Создание охватывающего некластеризованного индексавключая четыре столбца с именами.

Что касается производительности ваших вкладышей, возможно, вы можете предоставить некоторые метрики для определения того, что вы видите и как вы его измеряете?

Чтобы вы могли оценить, текущая запись вставки ETL для SQL Server составляет около 16 миллионов строк в секунду.Какие номера вы ожидаете и хотите увидеть?

0 голосов
/ 12 октября 2010

Учитывая тот факт, что name2 - name3 может быть нулевым, можно ли будет реструктурировать таблицу параметров:

TableParameter
  Id    (int, PRIMARY KEY, IDENTITY)
  Name  (string)
  Dimension int

Теперь вы можете индексировать ее и упростить запрос.(ГДЕ name = "TheNameIWant" И Dimension = "2")

(И если говорить об индексах, у вас есть индекс столбцы имен в таблице параметров?)

Где вы делаетефиксирует на вставке?если вы выполняете один оператор фиксации, группируйте несколько вставок в одну.

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

только некоторые идеи

hth

Марио

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...