Этот вопрос, кажется, действительно возникает здесь очень часто. Марк имеет правильный (и наиболее часто используемый) ответ, но позвольте мне попытаться добавить, что я могу, чтобы сделать это более ясным.
Сообщение об ошибке немного вводит в заблуждение. SQL Server сообщает, что у него недостаточно памяти для выполнения запроса, но на самом деле это означает, что у него недостаточно памяти для анализа запроса.
Когда дело доходит до выполнения запроса, SQL Server может использовать все, что ему нужно - гигабайты, если это необходимо. Разбор это другая история; сервер должен построить дерево разбора, и для этого имеется только очень ограниченный объем памяти. Я никогда не обнаруживал фактического предела, документированного где-либо, но для типичного пакета, полного операторов INSERT
, он не может обрабатывать более нескольких МБ за раз.
Поэтому мне очень жаль говорить вам об этом, но вы не можете заставить SQL Server выполнять этот сценарий в точности так, как он написан. Ни как, ни как, не важно, какие настройки вы настраиваете. Однако у вас есть несколько вариантов, чтобы обойти это:
В частности, у вас есть три варианта:
Используйте GO
операторов. Это используется SSMS и различными другими инструментами в качестве разделителя пакетов. Вместо одного дерева разбора, генерируемого для всего сценария, отдельные деревья разбора генерируются для каждого сегмента пакета, разделенного GO
. Это то, что делает большинство людей, и очень просто сделать сценарий безопасным с точки зрения транзакций, как продемонстрировали другие, и я не буду здесь повторяться.
Вместо генерации массивного скрипта для вставки всех строк храните данные в текстовом файле (т.е. через запятую). Затем импортируйте его с помощью утилиты bcp . Если вам нужно, чтобы это было «сценарием» - т.е. импорт должен происходить в том же сценарии / транзакции, что и оператор CREATE TABLE
, тогда используйте вместо него BULK INSERT . Хотя BULK INSERT
является незарегистрированной операцией, хотите верьте, хотите нет, но ее все же можно поместить в блок BEGIN TRAN
/ COMMIT TRAN
.
Если вы действительно, действительно хотите, чтобы 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
Надеюсь, это поможет вам встать на правильный путь. Я уверен, что это охватывает все ваши доступные варианты «в коробке» - помимо них, вам придется начать писать реальные прикладные программы или сценарии оболочки, чтобы выполнить работу, и я не думаю, что уровень сложности действительно оправдано здесь.