Каков наилучший способ архивировать все, кроме текущего года и разделить таблицу одновременно

23

задача

Архивируйте все, кроме скользящего 13-месячного периода, из группы больших таблиц. Архивные данные должны храниться в другой базе данных.

  • База данных находится в простом режиме восстановления
  • Таблицы имеют размер от 50 до нескольких миллиардов строк, а в некоторых случаях занимают сотни гигабайт каждая.
  • Таблицы в настоящее время не разделены
  • Каждая таблица имеет один кластеризованный индекс в столбце с постоянно увеличивающейся датой.
  • Каждая таблица дополнительно имеет один некластеризованный индекс
  • Все изменения данных в таблицах являются вставками
  • Цель состоит в том, чтобы минимизировать время простоя первичной базы данных.
  • Сервер 2008 R2 Enterprise

В «архивной» таблице будет около 1,1 млрд. Строк, в «живой» - около 400 млн. Очевидно, что архивная таблица со временем будет увеличиваться, но я ожидаю, что живая таблица тоже будет расти достаточно быстро. Скажите 50% в ближайшие пару лет как минимум.

Я думал о растянутых базах данных Azure, но, к сожалению, мы находимся на 2008 R2 и, вероятно, останемся там на некоторое время.

Текущий план

  • Создать новую базу данных
  • Создайте новые таблицы, разделенные по месяцам (используя дату изменения) в новой базе данных.
  • Переместите данные за последние 12-13 месяцев в разделенные таблицы.
  • Сделайте переименование своп из двух баз данных
  • Удалите перемещенные данные из теперь «архивной» базы данных.
  • Разбейте каждую из таблиц в «архивной» базе данных.
  • Используйте перестановки разделов для архивирования данных в будущем.
    • Я понимаю, что мне придется поменять данные, подлежащие архивированию, скопировать эту таблицу в базу данных архива, а затем поменять ее в таблице архива. Это приемлемо

Проблема: я пытаюсь переместить данные в исходные многораздельные таблицы (на самом деле я все еще делаю проверку концепции). Я пытаюсь использовать TF 610 (в соответствии с Руководством по производительности загрузки данных ) и INSERT...SELECTоператор для перемещения данных, изначально думая, что они будут минимально зарегистрированы. К сожалению, каждый раз, когда я пытаюсь, это полностью регистрируется.

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

Есть ли что-то, чего мне не хватает в моем общем плане, и является ли SSIS лучшим выбором для быстрого перемещения данных с минимальным использованием журнала (проблемы с пространством)?

Демо-код без данных

-- Existing structure
USE [Audit]
GO

CREATE TABLE [dbo].[AuditTable](
    [Col1] [bigint] NULL,
    [Col2] [int] NULL,
    [Col3] [int] NULL,
    [Col4] [int] NULL,
    [Col5] [int] NULL,
    [Col6] [money] NULL,
    [Modified] [datetime] NULL,
    [ModifiedBy] [varchar](50) NULL,
    [ModifiedType] [char](1) NULL
); 
-- ~1.4 bill rows, ~20% in the last year

CREATE CLUSTERED INDEX [AuditTable_Modified] ON [dbo].[AuditTable]
(   [Modified] ASC   )
GO


-- New DB & Code
USE Audit_New
GO

CREATE PARTITION FUNCTION ThirteenMonthPartFunction (datetime)
AS RANGE RIGHT FOR VALUES ('20150701', '20150801', '20150901', '20151001', '20151101', '20151201', 
                            '20160101', '20160201', '20160301', '20160401', '20160501', '20160601', 
                            '20160701') 

CREATE PARTITION SCHEME ThirteenMonthPartScheme AS PARTITION ThirteenMonthPartFunction
ALL TO ( [PRIMARY] );

CREATE TABLE [dbo].[AuditTable](
    [Col1] [bigint] NULL,
    [Col2] [int] NULL,
    [Col3] [int] NULL,
    [Col4] [int] NULL,
    [Col5] [int] NULL,
    [Col6] [money] NULL,
    [Modified] [datetime] NULL,
    [ModifiedBy] [varchar](50) NULL,
    [ModifiedType] [char](1) NULL
) ON ThirteenMonthPartScheme (Modified)
GO

CREATE CLUSTERED INDEX [AuditTable_Modified] ON [dbo].[AuditTable]
(
    [Modified] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON ThirteenMonthPartScheme (Modified)
GO

CREATE NONCLUSTERED INDEX [AuditTable_Col1_Col2_Col3_Col4_Modified] ON [dbo].[AuditTable]
(
    [Col1] ASC,
    [Col2] ASC,
    [Col3] ASC,
    [Col4] ASC,
    [Modified] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON ThirteenMonthPartScheme (Modified)
GO

Переместить код

USE Audit_New
GO
DBCC TRACEON(610);

INSERT INTO AuditTable
SELECT * FROM Audit.dbo.AuditTable
WHERE Modified >= '6/1/2015'
ORDER BY Modified
Кеннет Фишер
источник
RE «переместить данные»: чтобы минимизировать использование журнала, вы можете перемещать данные партиями, например, «Приблизительно 2» на dba.stackexchange.com/a/139009/94130 . На предмет разделения вы рассматривали разделенные представления?
Алекс
@ Алекс Да, я рассмотрел оба из них. Мой план резервного копирования состоит в том, чтобы перемещать данные партиями с использованием служб SSIS. И в этом конкретном случае моя проблема заключается именно в том, для чего построено разбиение. (быстрая загрузка / выгрузка данных с помощью переключения)
Кеннет Фишер

Ответы:

10

Почему вы не получаете минимальное ведение журнала?

Я считаю, что руководство по производительности загрузки данных , на которое вы ссылаетесь, является чрезвычайно ценным ресурсом. Однако он также не является на 100% полным, и я подозреваю, что сетка уже достаточно сложна, поэтому автор не добавил столбец, Table Partitioningчтобы выявить различия в поведении в зависимости от того, разбита ли таблица, получающая вставки. Как мы увидим позже, тот факт, что таблица уже секционирована, по-видимому, препятствует минимальному ведению журнала.

введите описание изображения здесь

Рекомендуемый подход

Основываясь на рекомендациях в Руководстве по производительности загрузки данных (включая раздел «Массовая загрузка секционированной таблицы»), а также обширном опыте загрузки секционированных таблиц с десятками миллиардов строк, я бы порекомендовал такой подход:

  • Создайте новую базу данных.
  • Создайте новые таблицы, разделенные по месяцам в новой базе данных.
  • Переместите данные за последний год следующим образом:
    • Для каждого месяца создайте новую таблицу кучи;
    • Вставьте этот месяц данных в кучу, используя подсказку TABLOCK;
    • Добавьте кластерный индекс в кучу, содержащую данные за месяц;
    • Добавьте проверочное ограничение, обеспечивающее, чтобы таблица содержала только данные за этот месяц;
    • Переключите таблицу в соответствующий раздел новой общей многораздельной таблицы.
  • Сделайте переименование своп из двух баз данных.
  • Усекать данные в теперь «архивной» базе данных.
  • Разбейте каждую из таблиц в «архивной» базе данных.
  • Используйте перестановки разделов для архивирования данных в будущем.

Отличия по сравнению с вашим оригинальным подходом:

  • Методология перемещения данных за последние 12-13 месяцев будет намного более эффективной, если вы загрузите в кучу по TABLOCKодному месяцу за раз, используя переключение разделов для помещения данных в разделенную таблицу.
  • A, DELETEчтобы убрать старую таблицу, будет полностью зарегистрирован. Возможно, вы можете TRUNCATEудалить таблицу или создать новую архивную таблицу.

Сравнение подходов для перемещения данных за последний год

Чтобы сравнить подходы за разумное время на моей машине, я использовал 100MM rowсгенерированный мной тестовый набор данных, который следует вашей схеме.

Как видно из результатов, приведенных ниже, происходит значительное повышение производительности и уменьшение количества записей в журнале путем загрузки данных в кучу с помощью TABLOCKподсказки. Есть дополнительное преимущество, если это делается по одному разделу за раз. Стоит также отметить, что метод «один раздел за раз» можно легко распараллелить, если вы запустите несколько разделов одновременно. В зависимости от вашего оборудования, это может дать хороший импульс; мы обычно загружаем как минимум четыре раздела одновременно на серверное оборудование.

введите описание изображения здесь

Вот полный тестовый скрипт .

Финальные заметки

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

Например, я выполнил рекомендованный подход на реальном сервере разработки (Dell R720) и увидел сокращение 76 seconds156 secondsмоего ноутбука). Интересно отметить, что оригинальный подход к вставке в многораздельную таблицу не испытал такого же улучшения и все же перенял только 12 minutesна сервере dev. Предположительно, это связано с тем, что этот шаблон дает план последовательного выполнения, а один процессор на моем ноутбуке может соответствовать одному процессору на сервере dev.

Джефф Паттерсон
источник
Еще раз спасибо Джефф. Я использую метод SWITCH. В частности, я использую SSIS и динамический SQL для параллельного запуска 13 месяцев.
Кеннет Фишер
1

Это может быть хорошим кандидатом на Бимл. Один из подходов заключается в создании повторно используемого шаблона, который будет переносить данные для одной таблицы в небольших диапазонах дат с контейнером For Each. Biml будет перебирать вашу коллекцию таблиц, чтобы создать идентичные пакеты для каждой подходящей таблицы. У Энди Леонарда есть вступление в его Серии Лестницы .

MattyZDBA
источник
0

Возможно, вместо создания новой базы данных, восстановите реальную базу данных в новую базу данных и удалите самые новые данные за 12-13 месяцев. Затем в вашей реальной базе данных удалите те данные, которые не содержатся в только что созданном вами районе архива. Если большие удаления являются проблемой, может быть, вы можете просто удалить наборы 10 КБ или больше с помощью сценария, чтобы сделать это.

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

Джон
источник
Я сделал это с меньшими базами данных раньше. Учитывая текущий размер и тот факт, что я хочу получить разделенные таблицы с обеих сторон, я думаю, что этот метод на самом деле занял бы больше времени и немного больше места (удвоил текущий размер БД при минимуме)
Кеннет Фишер