У меня есть таблица cats
с 42 795 120 строками.
Судя по всему, это много строк. Итак, когда я это сделаю:
/* owner_cats is a many-to-many join table */
DELETE FROM cats
WHERE cats.id_cat IN (
SELECT owner_cats.id_cat FROM owner_cats
WHERE owner_cats.id_owner = 1)
время запроса истекло :(
(изменить: мне нужно увеличить CommandTimeout
значение, по умолчанию всего 30 секунд)
Я не могу использовать TRUNCATE TABLE cats
, потому что не хочу отрывать кошек от других владельцев.
Я использую SQL Server 2005 с параметром «Модель восстановления», установленным на «Простое».
Итак, я подумал о том, чтобы сделать что-то вроде этого (выполнить этот SQL из приложения, кстати):
DELETE TOP (25) PERCENT FROM cats
WHERE cats.id_cat IN (
SELECT owner_cats.id_cat FROM owner_cats
WHERE owner_cats.id_owner = 1)
DELETE TOP(50) PERCENT FROM cats
WHERE cats.id_cat IN (
SELECT owner_cats.id_cat FROM owner_cats
WHERE owner_cats.id_owner = 1)
DELETE FROM cats
WHERE cats.id_cat IN (
SELECT owner_cats.id_cat FROM owner_cats
WHERE owner_cats.id_owner = 1)
У меня вопрос: каков порог количества строк, которое я могу DELETE
в SQL Server 2005?
Или, если мой подход не оптимален, предложите лучший подход. Спасибо.
Этот пост мне мало помог:
РЕДАКТИРОВАТЬ (6 августа 2010 г.):
Хорошо, я только что понял, снова прочитав приведенную выше ссылку, что у меня нет индексов для этих таблиц. Кроме того, некоторые из вас уже указали на эту проблему в комментариях ниже. Имейте в виду, что это фиктивная схема, поэтому даже id_cat
не является PK, потому что в моей реальной схеме это не уникальное поле.
Я поставлю индексы на:
cats.id_cat
owner_cats.id_cat
owner_cats.id_owner
Думаю, я все еще осваиваю это хранилище данных, и, очевидно, мне нужны индексы по всем JOIN
полям, верно?
Однако на выполнение этой пакетной загрузки у меня уходит несколько часов. Я уже делаю это как SqlBulkCopy
(кусками, а не сразу по 42 миллиона). У меня есть индексы и ПК. Я прочитал следующие сообщения, которые подтверждают мою теорию о том, что индексы замедляются даже при массовом копировании:
- SqlBulkCopy медленно, как меласса
- Какой самый быстрый способ массовой вставки большого количества данных в SQL Server (клиент C #)
Итак, я собираюсь DROP
свои индексы перед копированием, а затем CREATE
заново их, когда это будет сделано.
Из-за длительного времени загрузки мне потребуется некоторое время, чтобы проверить эти предложения. Я доложу о результатах.
ОБНОВЛЕНИЕ (07.08.2010):
Том предложил:
DELETE
FROM cats c
WHERE EXISTS (SELECT 1
FROM owner_cats o
WHERE o.id_cat = c.id_cat
AND o.id_owner = 1)
И все же без индексов для 42 миллионов строк потребовалось 13:21 мин: сек по сравнению с 22:08, как описано выше. Однако на 13 миллионов строк у него ушло 2:13 против 2:10 по моему старому пути. Это отличная идея, но мне все равно нужно использовать индексы!
Обновление (8.08.2010):
Что-то ужасно не так! Теперь, когда индексы включены, мой первый запрос на удаление занял 1: 9 час: мин (да, час!) по сравнению с 22:08 мин: сек и 13:21 мин. : сек по сравнению с 2:10 мин: сек для строк 42 мил и строк 13 мил соответственно. Сейчас я попробую выполнить запрос Тома с индексами, но он идет в неправильном направлении. Пожалуйста помоги.
Обновление (09.08.2010):
Удаление Тома заняло 1:06 ч: мин для строк 42 мил и 10:50 мин: сек для строк 13 мил с индексами по сравнению с 13:21 мин: сек и 2:13 мин: сек соответственно. Удаление в моей базе данных занимает больше времени, когда я использую индексы на порядок! Думаю, я знаю почему: размер моей базы данных .mdf и .ldf увеличился с 3,5 ГБ до 40,6 ГБ. Гб при первом (42 мил) удалении! Что я делаю не так?
Обновление (10.08.2010):
Из-за отсутствия каких-либо других вариантов я придумал, как мне кажется, тусклое решение (надеюсь, временное):
- Увеличьте время ожидания для подключения к базе данных до 1 часа (
CommandTimeout=60000;
по умолчанию было 30 секунд) - Используйте запрос Тома:
DELETE FROM WHERE EXISTS (SELECT 1 ...)
, потому что он работает немного быстрее DROP
все индексы и PK перед выполнением оператора удаления (???)- Запустить
DELETE
оператор CREATE
все индексы и PK
Кажется сумасшествием, но, по крайней мере, это быстрее, чем использование TRUNCATE
и начало моей нагрузки с самого начала с первого owner_id
, потому что один из моих owner_id
загружается за 2:30 ч: мин по сравнению с 17:22 мин: сек для процесса удаления. только что описанный с 42 миллионами строк. (Примечание: если мой процесс загрузки вызывает исключение, я начинаю с этого owner_id
, но я не хочу сдуть предыдущий owner_id
, поэтому я не хочу TRUNCATE
таблицу owner_cats
, поэтому я пытаюсь используйте DELETE
.)
Мы будем благодарны за дополнительную помощь :)
owner_cats.id_cat
,owner_cats.id_owner
иcats.id_cat
индексы?owner_cats.id_cat
первичный ключ? - person Thomas   schedule 07.08.2010JOIN
столбцы дляDELETE
SQL запросыDELETE
выполняются намного дольше! - person JohnB   schedule 16.08.2010