Sql Server - удалить столбец из VLT (очень большая таблица) - PullRequest
14 голосов
/ 14 февраля 2012

Может кто-нибудь посоветовать, пожалуйста, что лучше всего для достижения ниже:

Требование: отбросить 5 столбцов из VLT (почти 400 ГБ).

В тот момент, когда мы пытаемся сделать то же самое, мы сталкиваемся с проблемами с пространством при ПРОИЗВОДСТВЕ, ошибками тайм-аута (через SSMS)

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

если мы выполним эти операции через POWERSHELL, это будет лучше, чем в SSMS

Ограничение: ограниченное пространство на производстве, из-за этих операций быстро растет tempdb.

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

Привет

Ответы [ 5 ]

14 голосов
/ 15 февраля 2012

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

  1. Сделайте копию существующей очень большой таблицы нулевой длины, содержащую только те столбцы, которые вы хотите сохранить:

    select top 0 {{column subset}} into tbl_tableB from tableA
    

    Обязательно скопируйте все индексы, ограничения и т. Д. В новую таблицу. Столбцы идентификаторов будут надлежащим образом обрабатываться оператором SELECT...INTO.

  2. Переименовать исходную таблицу; мы заменим его видом на следующем шаге.

    exec sys.sp_rename @objname = 'tableA', @newname = 'tbl_tableA'
    
  3. Создать представление с использованием исходного имени таблицы и UNION ALL:

    create view tableA
    as
    select {{column subset}} from tbl_tableA
    union all
    select {{column subset}} from tbl_tableB
    

    Это будет поддерживать некоторый уровень совместимости с приложениями, запрашивающими данные. INSERTs, UPDATEs и DELETEs должны обрабатываться с помощью триггеров в представлении. UNION ALL предотвратит давление в базе данных tempdb, поскольку сортировки не будет (в отличие от прямой UNION), и у нас никогда не будет более одной копии строки одновременно.

  4. Используйте DELETE в сочетании с предложением OUTPUT, чтобы удалить данные в пакетах из исходной таблицы и одновременно вставить их в новую таблицу:

    BEGIN TRAN
    DELETE TOP (1000) /* or whatever batch size you want */
    FROM
        tbl_tableA
    OUTPUT (
        DELETED.{{column subset}} /* have to list each column here prefixed by DELETED. */
    )
    INTO
        tbl_tableB (
            {{column subset}} /* again list each column here */
        )
    /* Check for errors */
    /* COMMIT or ROLLBACK */
    /* rinse and repeat [n] times */
    
  5. Как только вы закончите с DELETEs / INSERTs, отбросьте представление, отбросьте исходную таблицу, переименуйте новую таблицу:

    drop view tableA
    drop table tbl_tableA
    exec sys.sp_rename @objname = 'tbl_tableB', @newname = 'tableA'
    

Главным достоинством этого подхода является то, что DELETE и INSERT происходят одновременно в одной транзакции, что означает, что данные всегда будут в согласованном состоянии. Вы можете увеличить размер пакета, изменив предложение TOP, что даст вам больше контроля над использованием и блокировкой журнала транзакций. Я протестировал этот точный подход на таблицах со столбцами идентификаторов и без них, и он прекрасно работает. На очень большом столе это займет некоторое время; может занять от нескольких часов до нескольких дней, но завершится с желаемым результатом.

11 голосов
/ 14 февраля 2012

Сама ALTER TABLE ... DROP является операцией только с метаданными, она будет выполняться почти мгновенно , пока она может получить эксклюзивную блокировку для таблицы , что означает, что все запросы, использующие таблицу, должны быть обработаны (завершено)).Но удаление столбца физически не удаляет их, см. столбцы таблицы SQL Server под капотом .

Следующим шагом является удаление физических столбцов, если это необходимо.Я призываю , если необходимо ', потому что, в зависимости от типа столбца, это может не стоить усилий.Для столбцов переменной длины вы можете восстановить пространство, выполнив DBCC CLEANTABLE.Но если вы отбросили столбцы фиксированного размера в несжатой таблице (без сжатия страницы или строки), то единственный способ освободить пространство - это перестроить таблицу (куча или кластерный индекс).Если таблица секционирована, вы можете попробовать перестроить автономно один раздел за раз (ALTER TABLE ... REBUILD PARTITION = N).Если нет, лучше всего перестраивать онлайн, если у вас нет столбцов типа MAX (это ограничение снято в SQL Server 2012 ).Оперативная перестройка генерирует большое количество журналов (по крайней мере в 1,5 раза больше данных), но оно фиксируется внутренне, поэтому обслуживание резервного копирования журнала может освободить пространство, и вы не получите 600 ГБ прироста журнала.Если перестроение в режиме онлайн невозможно и таблица не разбита на разделы, я сначала вернусь к решению очистить столбцы удаления.

Если очистка столбца является абсолютной необходимостью , и у вас нет альтернативы в Интернете, то у вас действительно впереди мир боли.Выполнение такой большой операции требует дней подготовки, тестирования и совсем не тривиально.Вам нужно будет создать новую таблицу с нужной структурой, начать переносить в нее данные партиями и настроить механизм отслеживания изменений, внесенных в уже скопированные данные, которые затем будут применены к копии.Когда все данные скопированы, и изменения, которые произошли с момента начала копирования, применяются, вы можете переключить старую и новую таблицу, используя sp_rename.В общем, вам будет намного лучше, если вы сможете использовать онлайн-опцию в продаже.

2 голосов
/ 14 февраля 2012

Я бы сказал, сочетание другой таблицы и пакетного задания.

1 - Создайте новую таблицу с желаемой структурой.Используйте тот же ключ кластеризованного индекса, что и в старой таблице.

2 - создайте представление для объединения старых и новых таблиц, чтобы иметь постоянный доступ к обеим при необходимости.Чтобы ограничить проблемы на производстве, вы можете назвать его так же, как исходную таблицу, и переименовать таблицу в _Old или что-то еще.Включайте только необходимые поля в представление, а НЕ поля, которые вы удаляете, очевидно.

3 - Внутри транзакции:

  • Вставьте количество строкк новой таблице (скажем, 1 м за раз или что-то)
  • Удалить из старой таблицы, JOIN добавив в новую таблицу

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

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

0 голосов
/ 14 февраля 2012

Не могу сказать, что у меня есть опыт работы с таблицами такого размера, но если бы это был я и искал что-то, чтобы попробовать, я бы попытался с помощью BCP передать данные (только те столбцы, которые вы хотите сохранить) в O / S файл, отбросьте таблицу и затем скопируйте данные обратно в новую таблицу с нужными мне столбцами. Конечно, это предполагает, что у вас есть возможность перевести сервер в автономный режим, пока вы выполняете это обслуживание (и что у вас есть хорошие резервные копии перед запуском).

0 голосов
/ 14 февраля 2012

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

Если вы не очень хорошо знакомы с секционированными таблицами и индексами, я настоятельно рекомендую эту превосходную техническую статью *1004* от Kimberly Tripp.

Вставляя данные в таблицы коммутаторов, выможно принудительно выполнить минимальное ведение журнала, выполнив следующие действия:

  1. Ваша таблица переключателей должна быть пустой.
  2. Ваша БД должна находиться в простом режиме восстановления
  3. Вынеобходимо использовать флаг трассировки 610 следующим образом:

    DBCC TRACEON (610)

  4. Вам необходимо использовать подсказку таблока на вашем столе следующим образом:

    INSERT newtable WITH (TABLOCK)
    SELECT col1, col2, col3, col4 
    FROM oldtable
    WHERE col1 BETWEEN min and max
    
  5. Таблица переключателей должна иметь кластеризованный индекс

Удачи.Я надеюсь, что это будет полезно.Я работаю с VLDB в SQL Server и обнаружил, что разметка очень важна, когда дело доходит до загрузки и перемещения данных.

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