задача
Архивируйте все, кроме скользящего 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
источник
Ответы:
Почему вы не получаете минимальное ведение журнала?
Я считаю, что руководство по производительности загрузки данных , на которое вы ссылаетесь, является чрезвычайно ценным ресурсом. Однако он также не является на 100% полным, и я подозреваю, что сетка уже достаточно сложна, поэтому автор не добавил столбец,
Table Partitioning
чтобы выявить различия в поведении в зависимости от того, разбита ли таблица, получающая вставки. Как мы увидим позже, тот факт, что таблица уже секционирована, по-видимому, препятствует минимальному ведению журнала.Рекомендуемый подход
Основываясь на рекомендациях в Руководстве по производительности загрузки данных (включая раздел «Массовая загрузка секционированной таблицы»), а также обширном опыте загрузки секционированных таблиц с десятками миллиардов строк, я бы порекомендовал такой подход:
Отличия по сравнению с вашим оригинальным подходом:
TABLOCK
одному месяцу за раз, используя переключение разделов для помещения данных в разделенную таблицу.DELETE
чтобы убрать старую таблицу, будет полностью зарегистрирован. Возможно, вы можетеTRUNCATE
удалить таблицу или создать новую архивную таблицу.Сравнение подходов для перемещения данных за последний год
Чтобы сравнить подходы за разумное время на моей машине, я использовал
100MM row
сгенерированный мной тестовый набор данных, который следует вашей схеме.Как видно из результатов, приведенных ниже, происходит значительное повышение производительности и уменьшение количества записей в журнале путем загрузки данных в кучу с помощью
TABLOCK
подсказки. Есть дополнительное преимущество, если это делается по одному разделу за раз. Стоит также отметить, что метод «один раздел за раз» можно легко распараллелить, если вы запустите несколько разделов одновременно. В зависимости от вашего оборудования, это может дать хороший импульс; мы обычно загружаем как минимум четыре раздела одновременно на серверное оборудование.Вот полный тестовый скрипт .
Финальные заметки
Все эти результаты в некоторой степени зависят от вашего оборудования. Однако мои тесты проводились на стандартном четырехъядерном ноутбуке с вращающимся дисководом. Вполне вероятно, что загрузка данных должна быть намного быстрее, если вы используете приличный сервер, который не имеет много другой нагрузки во время выполнения этого процесса.
Например, я выполнил рекомендованный подход на реальном сервере разработки (Dell R720) и увидел сокращение
76 seconds
(с156 seconds
моего ноутбука). Интересно отметить, что оригинальный подход к вставке в многораздельную таблицу не испытал такого же улучшения и все же перенял только12 minutes
на сервере dev. Предположительно, это связано с тем, что этот шаблон дает план последовательного выполнения, а один процессор на моем ноутбуке может соответствовать одному процессору на сервере dev.источник
Это может быть хорошим кандидатом на Бимл. Один из подходов заключается в создании повторно используемого шаблона, который будет переносить данные для одной таблицы в небольших диапазонах дат с контейнером For Each. Biml будет перебирать вашу коллекцию таблиц, чтобы создать идентичные пакеты для каждой подходящей таблицы. У Энди Леонарда есть вступление в его Серии Лестницы .
источник
Возможно, вместо создания новой базы данных, восстановите реальную базу данных в новую базу данных и удалите самые новые данные за 12-13 месяцев. Затем в вашей реальной базе данных удалите те данные, которые не содержатся в только что созданном вами районе архива. Если большие удаления являются проблемой, может быть, вы можете просто удалить наборы 10 КБ или больше с помощью сценария, чтобы сделать это.
Похоже, что ваши задачи разбиения не будут мешать друг другу и, по-видимому, будут применимы к любой базе данных после вашего удаления.
источник