Cette question semble en fait revenir de temps en temps ici. Marquer a la bonne réponse (et la plus couramment utilisée), mais laissez-moi essayer d'ajouter ce que je peux pour clarifier les choses.
Le message d'erreur est un peu trompeur. SQL Server vous indique qu'il n'a pas assez de mémoire pour exécuter la requête, mais ce que cela signifie vraiment, c'est qu'il n'a pas assez de mémoire pour analyser la requête.
Quand il s'agit de courir la requête, SQL Server peut utiliser tout ce qu'il veut - des gigaoctets si nécessaire. L'analyse est une autre histoire; le serveur doit construire un arbre d'analyse et il n'y a qu'une quantité très limitée de mémoire disponible pour cela. Je n'ai jamais trouvé la limite réelle documentée ailleurs que pour un lot typique rempli de INSERT
instructions, il ne peut pas gérer plus de quelques Mo à la fois.
Je suis donc désolé de vous le dire, mais vous ne pouvez pas faites en sorte que SQL Server exécute ce script exactement comme il est écrit. Pas question, pas comment, peu importe les paramètres que vous modifiez. Cependant, vous disposez de plusieurs options pour contourner ce problème :
Plus précisément, vous avez trois options :
-
Utilisez
GO
déclarations. Ceci est utilisé par SSMS et divers autres outils comme séparateur de lots. Au lieu qu'un seul arbre d'analyse soit généré pour l'ensemble du script, des arbres d'analyse individuels sont générés pour chaque segment du lot séparés parGO
. C'est ce que font la plupart des gens, et il est très simple de rendre le script sécurisé pour les transactions, comme d'autres l'ont démontré et je ne le répéterai pas ici. -
Au lieu de générer un script massif pour insérer toutes les lignes, conservez les données dans un fichier texte (c'est-à-dire séparés par des virgules). Ensuite, importez-le à l'aide de l'utilitaire bcp . Si vous avez besoin que cela soit "scriptable" - c'est-à-dire que l'importation doit se produire dans le même script/transaction que le
CREATE TABLE
instruction, puis utilisez BULK INSERT Au lieu. Bien queBULK INSERT
est une opération non journalisée, croyez-le ou non, elle peut toujours être placée dans unBEGIN TRAN
/COMMIT TRAN
bloquer. -
Si vous voulez vraiment, vraiment le
INSERT
être une opération enregistrée et que vous ne souhaitez pas que les insertions se produisent par lots, vous pouvez utiliser OPENROWSET pour ouvrir un fichier texte, un fichier Excel, etc. en tant que "tableau" ad hoc, puis insérez-le dans votre table nouvellement créée. Je suis normalement réticent à recommander l'utilisation deOPENROWSET
, mais comme il s'agit clairement d'un script administratif, ce n'est pas vraiment un problème majeur.
Les commentaires précédents suggèrent que vous n'êtes pas à l'aise avec #1, bien que cela puisse simplement être dû à une hypothèse incorrecte selon laquelle cela ne peut pas être fait en une seule transaction, auquel cas voir Thomas
la réponse. Mais si vous êtes déterminé à suivre une autre voie, je vous suggère d'aller avec #2, de créer un fichier texte et d'utiliser BULK INSERT
. Un exemple de script "sûr" serait :
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
J'espère que cela vous aidera à vous mettre sur la bonne voie. Je suis presque sûr que cela couvre toutes vos options "dans la boîte" disponibles - au-delà de celles-ci, vous devrez commencer à écrire des programmes d'application ou des scripts shell réels pour faire le travail, et je ne pense pas que ce niveau de complexité soit vraiment justifié ici.