SQL Server 2005 Ошибка 701 - недостаточно памяти - PullRequest
8 голосов
/ 19 февраля 2010

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

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

Я работаю с 4 ГБ ОЗУ, 64-битной Windows 7 Ultimate, Core2Duo T6400 (2 ГГц) ...

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

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

Любая идея будеточень ценится!

Ответы [ 4 ]

9 голосов
/ 17 марта 2010

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

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

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

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

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

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

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

  3. Если вы действительно, действительно хотите, чтобы INSERT была зарегистрированной операцией, и не хотите, чтобы вставки выполнялись партиями, тогда вы можете использовать OPENROWSET , чтобы открыть текст файл, файл Excel и т. д. в виде специальной таблицы, а затем вставьте ее в созданную вами таблицу. Обычно я не рекомендую использовать 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 голосов
/ 19 февраля 2010

Вы можете разбить файл на несколько пакетов - например, добавление оператора 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 голосов
/ 16 марта 2010

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

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

Это поможет освободить память.Кроме того, Microsoft выпускает исправление для решения этой проблемы в Sql Server 2005 (смотрите здесь ).Попробуйте установить исправление \ пакет обновления.

0 голосов
/ 11 марта 2010

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

SET XACT_ABORT ON
BEGIN TRAN

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

If @@TranCount > 0 Commit Tran

Если для XACT_ABORT установлено значение ON, любой оператор вставки, который не выполнится, откатит всю транзакцию.

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