2009-09-25 4 views
3

Скажем, я пишу запрос:MS SQL Server, многократная вставка

INSERT INTO DestinationTable 
(ColumnA, ColumnB, ColumnC, etc.) 
SELECT FROM SourceTable 
(ColumnA, ColumnB, ColumnC, etc.) 

И мой источник таблица имеет 22 миллионов строк.

SQL-сервер заполняет мой жесткий диск и ошибки.

Почему SQL-сервер не обрабатывает мой запрос?

Должен ли я использовать курсор и вставлять строку за раз?

PS - это SQL Express 2005, но я мог бы попробовать полную версию.

UPDATE: Я также хочу упомянуть, что моя исходная таблица занимает около 1 ГБ памяти, когда я смотрю на нее в студии управления. И все же мое 25 ГБ свободного дискового пространства каким-то образом заполняется? Я также использую две разные базы данных Source.mdf -> Destination.mdf, я не знаю, имеет ли это значение.

+0

Почему вы вставляя 22 миллионов строк, конечно, все, что не может быть необходимых данных. –

+1

К сожалению, это так. Я не могу дать специфику, но это каждый клиент для конкретной компании. – jonathanpeppers

+0

Вы пытаетесь скопировать таблицу? вы попробовали «выбрать»? –

ответ

8

Пакетное обновление ...

INSERT INTO DestinationTable 
    (ColumnA, ColumnB, ColumnC, etc.) 
SELECT TOP 100000 ColumnA, ColumnB, ColumnC, etc. 
FROM SourceTable 
WHERE NOT EXISTS (SELECT * 
    FROM DestinationTable 
    WHERE DestinationTable.KeyCols = SourceTable.KeyCols) 

WHILE @@ROWCOUNT <> 0 
    INSERT INTO DestinationTable 
     (ColumnA, ColumnB, ColumnC, etc.) 
    SELECT TOP 100000 ColumnA, ColumnB, ColumnC, etc. 
    FROM SourceTable 
    WHERE NOT EXISTS (SELECT * 
     FROM DestinationTable 
     WHERE DestinationTable.KeyCols = SourceTable.KeyCols) 

Есть варианты, чтобы иметь дело с контрольными точками, авторизуйтесь управлением файлами, если вам это нужно в одном TXN и т.д.

+0

Я думаю, что мое предложение курсора может быть немного менее сложным, чем это , Я попробую оба и посмотрю, что работает лучше. – jonathanpeppers

+6

Я думаю, что курсор займет полтора года, чтобы вставить все ваши данные;) – womp

+2

@ Jonathan.Peppers: CURSOR по-прежнему нужны ресурсы, блокировки, возможно, 22 м строк в tempdb зависят от того, как вы объявляете его – gbn

1

Этого блог post имеет информацию об импорте данных в SQL Сервер.

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

Я бы действительно проанализировал, нужны ли все данные.

+0

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

4

Вы можете копировать данные в файл в собственном формате (изменение изменено с Csv на native) и импортировать его обратно в новую таблицу.

Read up the BCP utility here.

+0

22 миллиона строк? – gbn

+0

Я мог бы также использовать USPS. – jonathanpeppers

+1

Ну, я бы использовал | delimted .txt вместо CSV и объемной вставки или SSIS, но BCP отлично работает. К Jonathan, я импортирую 22 миллиона файлов записей в мою базу данных, используя объемную вставку, и требуется 16 минут. – HLGEM

0

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

http://support.microsoft.com/kb/59462

Ключевой подход заключается в следующем:

DBOPTION 'SELECT INTO' истинной

http://www.mssqlcity.com/FAQ/Devel/select_into.htm

+0

Действительно? Это стандартный INSERT, не может быть «минимально зарегистрирован». А с SQL Server 2000 вы должны использовать ALTER DATABASE. – gbn

+0

... и KB является древним, и даже упоминается, когда применяется опция – gbn

2

Вы можете попробовать установить модель восстановления базы данных "Simple" вместо «Полный» (по умолчанию). Это делается на странице «Параметры» свойств базы данных в Management Studio. Это должно уменьшить размер журнала транзакций. После того, как вы закончите вставку, вы всегда можете вернуть модель восстановления в режим Full.

+0

. Я попробую и посмотрю, мне просто не нравится это решение, если оно заканчивается автоматизированной задачей. – jonathanpeppers

+1

Если БД находится в полном восстановлении, и были сделаны резервные копии журналов, тогда переход на Simple прерывает цепочку журналов. Это должно быть очень тщательно рассмотрено в производственной среде, когда требуется восстановление по времени. После того, как вы вернетесь к полной полной резервной копии базы данных, необходимо предпринять перезапуск цепи журнала и разрешить дальнейшие резервные копии журналов. – GilaMonster

1

Я настоятельно рекомендую вам установить модель восстановления базы данных BULK_LOGGED при выполнении таких операций с большими объемами данных.

По умолчанию - для базы данных установлено значение ПРОСТОТА или ПОЛНАЯ модель восстановления.

Полная модель восстановления, которая полностью регистрирует все транзакции, предназначена для нормального использования.

Модель восстановления с объемным журналом предназначена для временного использования во время большой объемной операции - при условии, что она относится к массовым операциям, которые подвержены влиянию модели восстановления с большим объемом (для получения дополнительной информации см. Операции, которые могут быть Минимально зашел на msdn.microsoft.com/en-us/library/ms191244.aspx).

BULK_LOGGED модель восстановления минимально регистрирует транзакции

вы можете сделать это, используя ниже фрагмент кода

--Determine the recovery model currently used for the database 

    SELECT name AS [Database Name], 
    recovery_model_desc AS [Recovery Model] 
    FROM sys.databases 
    WHERE name=<database_name> ; 

    --Remember this recovery model so that you can switch back to the same later 

    --set the database recovery model to BULK_LOGGED 

    ALTER DATABASE <database_name> SET RECOVERY BULK_LOGGED; 

    --Run your heavy data insert tasks 
    INSERT INTO DestinationTable 
    (ColumnA, ColumnB, ColumnC, etc.) 
    SELECT FROM SourceTable 
    (ColumnA, ColumnB, ColumnC, etc.) 

    /*Again set the database recovery model to FULL or SIMPLE 
    (the result which we had got from first query)*/ 

    ALTER DATABASE <database_name> SET RECOVERY FULL; 
    --OR 
    ALTER DATABASE <database_name> SET RECOVERY SIMPLE; 

* Примечание - Пожалуйста, держите терпение во время операции объемной обрабатываемой * [: P]

Я сделал это много раз раньше. Сообщите мне, помогло ли это вам.

Вы можете обратиться ниже статье MSDN для деталей переключения между моделями восстановления - Соображения при переключении с полной или неполным протоколированием модели восстановления в msdn.microsoft.com/en-us/library/ms190203.aspx

+0

Я попробую, установив его на SIMPLE, это не имеет особого эффекта. В конце концов, это по ошибке. – jonathanpeppers

+0

Offcourse. ПОЛНЫЕ и ПРОСТОЕ модели восстановления слишком отстают от BULK_LOGGED с точки зрения производительности для операций с объемными данными. – Aamod

+0

BULK_LOGGED был ближе, но не смог попасть в мою систему, и даже если бы это было сделано, мне не пришлось бы сокращать базу данных/файлы, чтобы получить ее до приемлемого размера? Я думаю, что доработка вставки, как говорит верхний ответ, - это путь. – jonathanpeppers

0

Проблема с INSERT INTO ... SELECT (22 миллиона строк) заключается в том, что все работает как одна транзакция. Таким образом, вы, вероятно, заполните журнал транзакций, даже если база данных находится в режиме простого восстановления.

Вставка одной строки за один раз - это ужасная идея, она будет навсегда.

Экспортировать данные с помощью BCP, а импорт - как BULK INSERT, вероятно, самый быстрый способ. Но для этого требуется научиться использовать служебную программу BCP.

Если вы решили сделать это в T-SQL, вы должны разбить его на партии. Метод INSERT ... SELECT TOP (n) ... WHERE NOT EXISTS в предыдущем ответе работает, но время выполнения для предложения WHERE может складываться. Чтобы сделать его немного более эффективным и сложнее, я иногда заполняю временную таблицу значениями pk для каждых n строк, используя ROW_NUMBER() OVER (ORDER BY pk) и WHERE rn% (n) = 0. Тогда вы можете использовать цикл с INSERT INTO ... SELECT ... WHERE pk> @a AND pk < = @b с соответствующим кодом для обновления переменных на каждой итерации из таблицы temp. Просто убедитесь, что вы не пропустите ни одной строки на первой или последней итерации.

Возможно, вы захотите сделать это в Integration Services, который также может выполнять объемные вставки. Существует белая бумага Microsoft где-то около загрузки терабайт данных за 30 минут или около того. Они экспортировали (BCP?) Исходные данные в несколько файлов и создали несколько таблиц с той же структурой, что и пункт назначения. Затем вставьте каждый файл в отдельную пустую таблицу, и все они могут выполняться как минимально зарегистрированные. И все эти импортные операции выполнялись как отдельные параллельные процессы. Наконец, используйте команды разбиения таблиц, чтобы объединить каждую таблицу импорта в таблицу назначения.

нагрузки терабайт в течение 30 минут: https://technet.microsoft.com/en-us/library/dd537533(v=sql.100).aspx

Смежные вопросы