Самый эффективный (быстрый) T-SQL УДАЛЯЕТ для многих строк?

Вам просто нужен цикл для проверки ... Примерно так:

foreach(var column in t.Columns.Cast().ToArray()) {
    if (t.AsEnumerable().All(dr => dr.IsNull(column)))
        t.Columns.Remove(column);
}

Кредиты: здесь

5
задан John Dibling 9 March 2010 в 17:18
поделиться

8 ответов

ИЛИ (или в) почти работает, как будто каждый ИЛИ операнд - различный запрос. Таким образом, это превращается в сканирование таблицы, и для каждой строки, база данных должна протестировать каждого ИЛИ операнд как предикат, пока это не находит соответствие или исчерпывает операнды.

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

Quassnoi делает интересное предложение - для использования таблицы - но так как он затем использует INS и ORs, он выходит то же.

Но попробуйте это.

Составьте новую таблицу, которая зеркально отражает Вашу реальную таблицу. Назовите это u_real_table. Индексируйте его на теге и longTag.

Поместите все свои входящие данные в u_real_table.

Теперь, когда Вы готовы сделать свою объемную вещь, вместо этого присоединиться к зеркальной таблице o реальная таблица на теге. От реальной таблицы удалите все tag'd строки в u_real_table:

delete real_table from real_table a 
   join u_real_table b on (a.tag = b.tag);
insert into real_table select * 
   from u_real_table where tag is not null;

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

Сначала мы удалили все новое, затем мы вставили новые замены. Мы могли также сделать обновление здесь. То, которое быстрее, зависит от Вашей структуры таблицы и ее индексов.

Мы не должны были писать сценарий, чтобы сделать это, мы просто, должно быть, вставили записи в u_real_table.

Теперь мы делаем то же самое для longTags:

delete real_table from real_table a 
   join u_real_table b on (a.longTag = b.longTag);
insert into real_table select * 
   from u_real_table where longTag is not null;

Наконец, мы убираем u_real_table:

delete from u_real_table;

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

Этот метод уменьшает Ваш физический труд, уменьшает возможность ручной ошибки и имеет некоторый шанс ускорения удаления.

Обратите внимание, что это полагается на пропавших без вести тегов и longTags, правильно являющегося пустым, не нуль или пустая строка.

4
ответ дан 18 December 2019 в 06:52
поделиться

Я думаю, разделяя гигантский Оператор удаления на 2, УДАЛЯЮТ, может помочь.

1 УДАЛЯЮТ для контакта с тегом, и отдельное УДАЛЯЮТ для контакта с longTag. Это помогло бы SQL-серверу принять решение использовать индексы эффективно.

Конечно, можно все еще запустить эти 2 Оператора удаления в распространение в прямом и обратном направлениях на 1 дБ.

Надеюсь, это поможет

5
ответ дан 18 December 2019 в 06:52
поделиться

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

http://www.sqlservervideos.com/video/nibbling-deletes

3
ответ дан 18 December 2019 в 06:52
поделиться

Что-то вроде этого могло оптимизировать процесс (Вы просто ВСТАВИТЕ строки, неважно, если они уже будут существовать - никакая потребность в первичном Операторе удаления):

CREATE TRIGGER dbo.TR_MyTable_Merge 
   ON  dbo.MyTable 
   INSTEAD OF INSERT
AS 
BEGIN
  SET NOCOUNT ON;

  BEGIN TRANSACTION

  DELETE MyTable 
  FROM   MyTable t INNER JOIN inserted i ON t.tag = i.tag 

  DELETE MyTable 
  FROM   MyTable t INNER JOIN inserted i ON t.longTag = i.longTag

  INSERT MyTable 
  SELECT * FROM inserted

  COMMIT TRANSACTION

  SET NOCOUNT OFF;
END

Править: Ранее Объединенный Оператор удаления разбит в два отдельных оператора, для включения оптимального индексного использования.

Не использование УДАЛЯЕТ вообще, а скорее UPDATEing, затронутые/дублирующиеся строки на месте будут легче на индексах.

3
ответ дан 18 December 2019 в 06:52
поделиться

Используя ORs может вызвать сканирование таблицы - можно ли разбить его в четыре оператора? Обертывание каждого в транзакции может также ускорить вещи.

DELETE from MyRecords
WHERE tag = 1

DELETE from MyRecords
WHERE tag = 2

DELETE from MyRecords
WHERE tag = 555

DELETE from MyRecords
WHERE longTag = 'LongTag1'
2
ответ дан 18 December 2019 в 06:52
поделиться

Возможно:

DELETE FROM MyRecords
WHERE  tag IN (1, 2, 555) -- build a list
OR longTag IN ('LongTag1')

Я подозреваю, что индексы помогли бы Вашему, удаляет, но решительно замедлите свои вставки, таким образом, я не играл бы с так слишком много. Но затем моя интуиция еще не точно прекрасна, Вы смогли настраивать FillFactor или другие объекты для обхождения той проблемы и одной вещи, я действительно знаю наверняка это, что Вы действительно хотите представить обоих так или иначе.

Другая опция состоит в том, чтобы загрузиться, новые вставки во временную таблицу (назвал что-то как InputQueue), и затем присоединитесь к временной таблице на MyRecords для обработки обновлений фильтрации. Это также помогло бы сделать обновление на двух шагах: Вы могли удалить Теги и longTags как отдельные операции, и это могло бы оказаться намного более эффективным.

3
ответ дан 18 December 2019 в 06:52
поделиться

Кажется, что Ваша таблица не индексируется на (tag) и (longTag)

Сборка два индекса: один на (tag), один на (longTag)

Если Вы планируете удалить действительно большое количество записей, затем объявить две табличных переменные, заполнить их значениями и удалить как это:

DECLARE @tag TABLE (id INT);
DECLARE @longTag TABLE (id VARCHAR(50));

INSERT
INTO  @tag
VALUES (`tag1`)

INSERT
INTO  @tag
VALUES (`tag2`)

/* ... */

INSERT INTO @longTag
VALUES ('LongTag1')

/* ... */


DELETE
FROM    MyRecords r
WHERE   r.tag IN (SELECT * FROM @tag)
        OR r.longTag IN (SELECT * FROM @longTag)

Можно также попытаться выполнить с двумя передачами DELETE:

DELETE
FROM    MyRecords r
WHERE   r.tag IN (SELECT * FROM @tag)

DELETE
FROM    MyRecords r
WHERE   r.longTag IN (SELECT * FROM @longTag)

и посмотрите, какие операторы выполняет дольше, чтобы видеть, существует ли проблема с индексами.

2
ответ дан 18 December 2019 в 06:52
поделиться

Индексация:

Рассмотрите использование индексируемого сохраненного вычисляемого столбца для longTag, который хранит контрольную сумму longTag. Вместо того, чтобы индексировать 'LongTag1', Вы индексируете 4-байтовое международное значение (86939596).

Затем Ваши поиски [надо надеяться, *] быстрее, и просто необходимо включать значение longTag в то, чтобы запрашивать/удаление. Ваш код был бы немного более сложным, но индексация, вероятно, будет намного более эффективной.

* Требует тестирования

1
ответ дан 18 December 2019 в 06:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: