Эффективный способ изменить таблицу 100 ГБ - PullRequest
7 голосов
/ 13 сентября 2010

У нас есть несколько баз данных, которые хранят от 10 до 100 гигабайт данных в одной из таблиц. Он содержит данные изображения. Проблема в том, что многие из этих баз данных были созданы неправильно. По сути, первичный ключ на самом деле не первичный ключ. Они были созданы с уникальным индексом на обнуляемый столбец. И некоторые из них имеют int как первичный ключ вместо bigint.

Итак, мы медленно прорабатывали и исправляли эти базы данных. Они работают от SQL Server 2000 до SQL Server 2008, хотя большинство из них с проблемами первичного ключа относятся к SQL Server 2000. Проблема в том, что мы не хотим блокировать базу данных на целый день, пока она преобразует таблицу. Мы прошли через несколько стратегий:

  1. Скажите SQL Server напрямую изменить тип столбца. Это блокирует таблицу до тех пор, пока она не будет завершена, и во многих случаях после того, как она оставлена ​​на ночь, она все еще не была завершена.

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

  3. Вставьте 100 строк за раз, когда строки не существуют в целевой таблице. Положительным моментом является то, что они могут продолжать использовать базу данных, пока она продолжается (с большим падением производительности), и что она может быть остановлена ​​и перезапущена произвольно в любой момент, и это предотвращает более 100 ГБ файлов журнала. Это то, что мы делаем в настоящее время, но поиск первых 100 строк, которые не существуют, становится действительно очень медленным, поскольку целевая таблица становится все больше и больше. ОБНОВЛЕНИЕ СТАТИСТИКА и DBCC INDEXDEFRAG помогают значительно, но в самой последней попытке мы дошли до того, что даже 100 изображений за раз сидели там, не отвечая.

    INSERT INTO %s  
      SELECT TOP 100 Source.*  
      FROM %s AS Source WITH (NOLOCK)  
      LEFT OUTER JOIN %s AS Target WITH (NOLOCK) ON Source.DocumentID = Target.DocumentID  
      WHERE Target.DocumentID IS NULL  
      ORDER BY Source.DocumentID  
    

Итак, вопрос в том, есть ли опция, которая может копировать объемные данные эффективным и возобновляемым способом? Он не должен быть точным на 100%, мы всегда можем вернуться и исправить любые расхождения в конце, если он выполняет 99% работы.

1 Ответ

3 голосов
/ 13 сентября 2010

Соединение является проблемой.Не делай этого.Просто переберите вашу текущую таблицу, используя некоторый разумный интервал, используя current кластерный индекс.Примерно так:

Declare @idrange int;
Set @idrange = 1;

WHILE @idrange < 10000000

INSERT INTO Destination
  SELECT *  
  FROM Source
  WHERE DocumentID between @idrange and @idrange + 999
  ORDER BY Source.DocumentID  

Set @idrange = @idrange + 1000
End 

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

РЕДАКТИРОВАТЬ : изменил интервал диапазона, чтобы предотвратить наложение (так как BETWEEN включает в себя конечные точки)

Одно последнее уточнение: общий смысл моего примера сценария заключается в том, что вы просто хотите просмотреть текущие записив некотором разумном порядке, и поместите их все в новый стол партиями.Нет смысла продолжать проверять таблицу назначения каждый раз, так как вы уже должны знать, что вы положили туда, а что еще осталось.В большинстве случаев имеет смысл использовать кластеризованный индекс (если он есть), поскольку это означает, что он может проходить по физическому порядку таблицы без поиска закладок.Если в таблице нет кластера, просто используйте то, что имеет смысл (ваш ПК, вероятно).

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