Проблема выполнения запроса к большой таблице в MS SQL 2005 с использованием всех ресурсов сервера - PullRequest
0 голосов
/ 01 марта 2011

У меня есть база данных MSSQL 2005 с гигабайтами лишенных данных.Эти неверные данные приводят к тому, что с базой данных становится трудно работать, на резервное копирование уходит 4 часа, а на восстановление - 7 часов.Все неверные данные находятся в одной таблице.

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

Insert databaseB.dbo.table (col1,col2) 
select col1,col2  from databaseA.dbo.table

Моя последняя попытка выполнить вышеупомянутый запрос выполнялась в течение 12 часов без завершения, прежде чем мне пришлось отменить и перезапустить службы SQL, поскольку любое приложение, котороебаза данных на этом сервере не будет отвечать.

После завершения этой операции я буду запускать простое удаление «delete databaseA.dbo.table where condition = 1», которое в прошлый раз, когда я пытался, также заблокировало сервер.

У меня нетМне нужны какие-либо блокировки таблицы, которые я пытаюсь обновить.

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

Мне пришло в голову сделать резервную копию и восстановить базу данных в другом месте.Обрежьте таблицу и затем импортируйте правильные данные обратно в соответствующую таблицу.Но поскольку выполнение шага 1 займет не менее 11 часов, а шаг 2 неизвестной длины, мне не нравится этот параметр.

Ответы [ 4 ]

2 голосов
/ 01 марта 2011

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

Курсор см. Здесь: http://msdn.microsoft.com/en-us/library/ms180169.aspx

Цикличность:

  1. Выберите 10 строк
  2. Импортируйте их в новую таблицу
  3. Удалить эти 10 строк

    WHILE (SELECT COUNT(*) FROM YOUR_BAD_RECORDS) > 0
    BEGIN
        INSERT INTO TABLE...SELECT TOP 10 * FROM BAD_RECORDS
    END
    

Делайте это, пока работа не будет завершена. Это займет больше времени, но не заблокирует ресурсы сервера и не позволит другим системам получить доступ к БД.

1 голос
/ 02 марта 2011

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

Я предлагаю пошаговый процесс для перемещения этих записей. Ваши теги указывают, что вы используете SQL Server 2005, который поддерживает предложение OUTPUT, поэтому вы можете удалить старые записи и вставить их в архивную таблицу за один раз. Выберите количество записей, которые кажется разумным делать одновременно, и если вы используете подсказку блокировки READPAST, вы не будете заблокированы для записей, заблокированных другими пользователями. Просто запустите свой пакет столько раз, сколько необходимо, возможно, как запланированное задание. Конечно, убедитесь, что в предложении WHERE выбраны только записи, которые вы хотите заархивировать.

DELETE TOP (10000) FROM dbo.Valid_Date WITH (READPAST)
OUTPUT 
    DELETED.valid_date, DELETED.valid_date_KEY
    INTO dbo.Archive_Of_Valid_Date(valid_date, valid_date_KEY)
WHERE 
    valid_date < '19800101'

Отредактировано, чтобы расширить комментарий Мэтью к моему ответу


Использование COUNT (*) для определения того, нужно ли выполнять какую-либо работу, не является бесплатным, поэтому большую часть времени вы можете либо использовать EXISTS (который закорачивается, как только будет найдена любая соответствующая запись), либо использовать @@ rowcount после выписок

WHILE (SELECT COUNT() FROM DatabaseA.dbo.table WHERE Condition=1) > 0 
BEGIN 
    DELETE TOP (100) FROM DatabaseA.dbo.table WITH (READPAST)
    OUTPUT 
        DELETED.x, DELETED.y
        INTO ArchiveDB.dbo.table(x, y)
    WHERE 
        condition = 1
END

Попытка:

WHILE (1 = 1)
BEGIN 
    DELETE TOP (100) FROM DatabaseA.dbo.table WITH (READPAST)
    OUTPUT 
        DELETED.x, DELETED.y
        INTO ArchiveDB.dbo.table(x, y)
    WHERE 
        condition = 1

    IF(@@rowcount <= 0)
        break;
END

или

WHILE (EXISTS(SELECT * FROM DatabaseA.dbo.table WHERE Condition=1)) 
BEGIN 
    DELETE TOP (100) FROM DatabaseA.dbo.table WITH (READPAST)
    OUTPUT 
        DELETED.x, DELETED.y
        INTO ArchiveDB.dbo.table(x, y)
    WHERE 
        condition = 1
END
0 голосов
/ 02 марта 2011

В вместо удаления после, просто не вставляйте то, что будет удалено.

Insert databaseB.dbo.table (col1,col2) 
select col1,col2  from databaseA.dbo.table
where condition <> 1
0 голосов
/ 01 марта 2011

Удалить все индексы и внешние ключи из таблицы назначения.Воссоздать после очистки таблицы.

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