2010-02-19 4 views
8

я в настоящее время имеющий следующее сообщение об ошибке при выполнении .sql файл с примерно 26 Мб на SQL Server 2005:SQL Server 2005 Ошибка 701 - из памяти

Msg 701, Level 17, State 123 
There is insufficient system memory to run this query. 

Я работаю с 4 Гб оперативной памяти, 64-битной Windows 7 Ultimate, Core2Duo T6400 (2GHz) ...

Есть ли способ выполнить его без получения этого сообщения (возможно, заставить SQL Server использовать файл подкачки?) Или способ выполнить его по частям (например, 100 запросов время) ...

Файл в основном CREATE TABLE, за которым следуют тысячи INSER T, и у меня их много (преобразованные .DBF-файлы в SQL-запросы с использованием ABC DBF Converter)

Любая идея будет очень признательна!

ответ

9

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

Сообщение об ошибке немного вводит в заблуждение. SQL Server сообщает вам, что у него недостаточно памяти для . Запустите запрос, но на самом деле это означает, что у него недостаточно памяти для . Проанализируйте запрос.

Когда дело доходит до работает запрос, SQL Server может использовать все, что он хочет - гигабайт, если необходимо. Размышление - это еще одна история; сервер должен построить дерево синтаксического анализа, и для этого имеется только ограниченный объем памяти. Я никогда не обнаружил, что фактический предел документирован где угодно, но для типичной партии, полной INSERT, она не может обрабатывать более нескольких МБ за раз.

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

В частности, у вас есть три варианта:

  1. Используйте GO заявления. Это используется SSMS и другими инструментами в качестве разделителя партий. Вместо единого дерева разбора, сгенерированного для всего сценария, для каждого сегмента партии, разделенного GO, генерируются отдельные деревья синтаксического анализа. Это то, что делают большинство людей, и очень просто сделать сценарий безопасным для транзакций, как показали другие, и я не буду здесь повторять.

  2. Вместо того, чтобы генерировать массивный скрипт для вставки всех строк, сохраняйте данные в текстовом файле (то есть разделенном запятой). Затем импортируйте его с помощью bcp utility. Если вам нужно, чтобы это было «scriptable», то есть импорт должен происходить в том же скрипте/транзакции, что и оператор CREATE TABLE, а затем использовать BULK INSERT. Хотя BULK INSERT является незарегистрированной операцией, верьте или нет, ее все равно можно разместить в блоке BEGIN TRAN/COMMIT TRAN.

  3. Если вы действительно, действительно хотите INSERT быть авторизован операция, и не хотят, чтобы Вставки произойти в партиях, то вы можете использовать OPENROWSET, чтобы открыть текстовый файл, первенствует файл и т.д. как ad-hoc "table", а затем вставьте это в свою недавно созданную таблицу. Обычно я не рекомендую использовать OPENROWSET, но поскольку это явно административный скрипт, это не является серьезной проблемой.


Предыдущие комментарии предполагают, что вам неудобно с # 1, хотя это может быть просто из-за неправильного предположения, что это не может быть сделано в рамках одной транзакции, в этом случае см Thomas ' ответ. Но если вы мертвы, идя по другому пути, я предлагаю перейти с №2, создав текстовый файл и используя BULK INSERT. Примером «безопасного» сценария будет:

BEGIN TRAN 

BEGIN TRY 

    CREATE TABLE MyTable (...) 

    BULK INSERT MyTable 
    FROM 'C:\Scripts\Data\MyTableData.txt' 
    WITH (
     FIELDTERMINATOR = ',', 
     ROWTERMINATOR = '\r\n', 
     BATCHSIZE = 1000, 
     MAXERRORS = 1 
    ) 

    COMMIT 

END TRY 

BEGIN CATCH 

    ROLLBACK 

END CATCH 

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

4

Вы можете разбить файл на несколько партий - например. добавление заявления go после каждой тысячи вставок

, например.

insert db..table(field list) values ... 
insert db..table(field list) values ... 
go 
insert db..table(field list) values ... 
... 
insert db..table(field list) values ... 
go 

Другим способом может быть использование массовой загрузки, например. BCP

+0

До тех пор, пока он не будет отредактирован, он означает ДОБАВИТЬ инструкцию 'GO' после каждой тысячи вставки. –

+0

Спасибо Alex - обновлено как предложено – Mark

+0

Я уже использовал операторы GO для решения проблемы, но я не хочу использовать пакетный запуск, потому что, если у меня есть ошибка, у меня будут проблемы с откатом транзакций ... – Tufo

0

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

SET XACT_ABORT ON 
BEGIN TRAN 

Insert ... 
Insert ... 
Insert ... 
... 
GO 
Insert .. 
Insert .. 
Insert .. 
GO 

If @@TranCount > 0 Commit Tran 

С XACT_ABORT установлено значение ON, любая вставка заявление что не удастся отменить всю транзакцию.

-1

Вы можете добавить DBCC команды между вашими SQL запросов, как:

DBCC FREESYSTEMCACHE ('ALL') 
GO 
DBCC FREESESSIONCACHE 
GO 
DBCC FREEPROCCACHE 
GO 

Это поможет освободить память. Кроме того, корпорация Майкрософт выпустила исправление для решения этой проблемы на Sql Server 2005 (Look here). Попробуйте установить Hotfix \ Service Pack.

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