Mémoire utilisée non libérée après une insertion SQL BULK / export BCP

10

J'ai créé une table SQL très basique comme suit

CREATE TABLE [dbo].[TickData](
[Date] [varchar](12) NULL,
[Time] [varchar](12) NOT NULL,
[Symbol] [varchar](12) NOT NULL,
[Side] [varchar](2) NOT NULL,
[Depth] [varchar](2) NOT NULL,
[Quote] [varchar](12) NOT NULL,
[Size] [varchar](18) NOT NULL
    ) ON [PRIMARY]

J'ai ensuite effectué une insertion en vrac de 3 Go

    BULK
    INSERT TickData
    FROM 
    'C:\SUMO.csv'
    GO

Ensuite, l'utilisation de la RAM pour le serveur SQL est passée à Skyrock, mangeant environ 30 Go de RAM:

entrez la description de l'image ici

entrez la description de l'image ici

Je préfère penser qu'il s'agit d'un comportement anormal et que des mesures peuvent être prises pour éviter cela.

EDIT:
Ok, cela semble être le comportement par défaut. C'est suffisant.
Cependant, pourquoi la mémoire n'est-elle pas libérée longtemps après la fin de l'insertion en bloc?

Quelques considérations supplémentaires:
En ce qui concerne les commentaires concernant le serveur SQL libérant de la mémoire lorsqu'elle est "informée" par le système d'exploitation, mon expérience pratique sur un serveur Xeon à 24 cœurs 32 Go prouve que cela est inexact: une fois qu'un extrait BCP Memory-Voracious est terminé J'ai un pool d'instances .Net de mon application de traitement de données qui doivent traiter les données extraites, et elles sont étouffées / se battent pour partager la mémoire restante pour essayer d'effectuer leurs travaux, ce qui prend plus de temps que lorsque SQL Server est tourné désactivé et la mémoire est disponible pour toutes les applications à partager. Je dois arrêter l'Agent SQL Server pour que tout se passe bien et empêcher les applications de se bloquer pour Articiallt, à l'origine de l'exception OutOfMemmroy. En ce qui concerne le plafonnement / limitation de la mémoire brutale artificielle, si la mémoire libre est disponible, pourquoi ne pas l'utiliser? Idéalement, il serait préférable de s'adapter de manière dynamique à ce qui est disponible plutôt que d'être limité de manière "aléatoire". Mais je suppose que cela est intentionnel, donc le dossier est clos sur ce dernier point.

Mehdi LAMRANI
la source
6
Pourquoi SQL Server devrait-il libérer de la mémoire? S'il a eu besoin de la mémoire pour effectuer cette opération une fois, il en aura de nouveau besoin. Si SQL Server a libéré la mémoire, à quoi l'utiliseriez-vous? Pourquoi la mémoire doit-elle être libre? Si vous utilisez la mémoire pour autre chose, cette insertion en bloc s'exécute à nouveau, que devrait-il se passer?
Aaron Bertrand
La seule action que vous pouvez prendre pour éviter cela est de définir la taille maximale de la mémoire. Pour "récupérer" la mémoire, vous pouvez redémarrer le service SQL Server. Évidemment, cela libérera la mémoire et lorsque le service redémarrera, il allouera la mémoire normalement.
TMN
J'ai nettoyé le dernier montage. Si vous souhaitez avoir un argument / discussion sur les mérites ou les problèmes de codage de SQL Server (ou de tout autre moteur de base de données), veuillez trouver un meilleur endroit pour le faire. La question d'origine a été répondue, apparemment correctement et suffisamment. Si ce Q continue de glisser, il peut se verrouiller.
JNK
Il n'y a rien de mal à vouloir connaître les réponses et discuter des méthodologies, mais pas ici sur un site de questions / réponses. Vous pouvez certainement avoir cette discussion dans le chat ou un forum quelque part, mais Stack Exchange est un peu plus structuré et les questions de discussion seront fermées très rapidement.
JNK
3
De plus, en tant que non modérateur, je me demande pourquoi vous exécutez des choses non SQL sur votre serveur? La boîte doit être réservée JUSTE pour SQL Server, c'est comme DBA 101. Le moteur n'a pas été conçu pour un environnement de ressources partagées.
JNK

Réponses:

12

Il est normal que SQL Server alloue autant de mémoire que possible dans son pool de tampons. Les bases de données fonctionnent mieux avec beaucoup de mémoire tampon. Si vous souhaitez modifier le comportement, vous pouvez définir le paramètre «mémoire maximale du serveur» . Une bonne lecture de fond à ce sujet est ici.

Matt Whitfield
la source
1
En ce qui concerne votre montage, le commentaire d'Aaron est bon. La raison en est qu'il est inutile qu'un serveur de base de données libère de la mémoire. SQL Server répondra à la pression de la mémoire et libérera de la mémoire si cela est vraiment nécessaire, mais cela ne devrait vraiment pas être nécessaire.
Matt Whitfield
@MikaJacobi Désolé, mais votre deuxième modification est tout simplement erronée. Du point de vue d'un développeur, je comprends votre point de vue, mais il y a une différence entre créer un tas d'applications qui coexistent et un service serveur qui devrait vraiment être le seul service consommant de la mémoire sur la machine. Si vous voulez que SQL Server se comporte comme une application "normale", définissez la mémoire maximale et éloignez-vous. Votre question était de savoir pourquoi cela fonctionne de cette façon, et c'est une réponse. Si votre question est maintenant "eh bien je n'aime pas que ça fonctionne comme ça" - désolé, mais ce n'est plus une question.
Aaron Bertrand
C'est suffisant. Mon point de vue est simplement qu'il devrait y avoir une option pour l'activer ou le désactiver, et l'hypothèse que le serveur SQL est la seule application sur un serveur est vraiment abusive (cela peut être vrai pour les grandes entreprises avec de grands réseaux, mais ce n'est pas le seul possible ni la configuration la plus courante)
Mehdi LAMRANI
Je ne comprends toujours pas pourquoi vous avez besoin de SQL Server pour libérer de la mémoire. Si d'autres applications en ont besoin, elles le reprendront de SQL Server et SQL Server se conformera. Jusqu'à ce que ces autres applications en aient besoin, à quoi sert la libération de la mémoire?
Aaron Bertrand
1
@AaronBertrand Ok, je me trompe peut-être, mais comme indiqué dans ma nouvelle édition, ce n'est pas ce dont j'ai été témoin: la mémoire n'a pas été libérée lorsque d'autres applications en avaient à peine besoin, provoquant des pannes de mémoire (d'où mon mécontentement ...) fermer le sujet, je suppose qu'il n'y a pas vraiment besoin de discuter plus que cela.
Mehdi LAMRANI
7

Si vous voulez vraiment que le système d'exploitation récupère la mémoire de SQL Server, prenez un gros fichier de 20 Go et copiez-le sur le réseau. SQL Server libère la mémoire selon les besoins du système d'exploitation. Mais je regarderais une variété de compteurs de performances pendant que cela se passe et je verrais comment les performances de votre BULK INSERT changent si vous l'exécutez à nouveau pendant la copie ou immédiatement après.

Si vous souhaitez le faire manuellement, vous devez définir une limite inférieure sur le paramètre de mémoire maximale du serveur SQL Server et redémarrer le service. Désormais, SQL Server n'utilisera pas 28 Go même s'il en a besoin. Mais cela semble limiter artificiellement SQL Server.

Ce que vous semblez attendre, c'est un comportement plus flexible, où vous pouvez avoir de la mémoire libre une partie du temps. Dans quel but? Est-ce comme réduire un fichier de base de données pour libérer de l'espace disque que vous ne pouvez pas utiliser à d'autres fins parce que le fichier de base de données va se développer à nouveau?

C'est drôle, si vous tapez une recherche Google pour "pourquoi SQL Server ne fonctionne pas", l'auto-complétion la plus courante est "libérer de la mémoire".

Aaron Bertrand
la source
"Ce que vous semblez attendre, c'est un comportement plus flexible." Exactement. Je veux que SQL Server utilise toute la mémoire disponible lorsqu'elle est disponible, mais lorsque ces moments lourds sont terminés, pour revenir à l'état "veille" et laisser les autres applications nécessitant de la mémoire faire leur travail confortablement (vous pouvez consulter mon nouvelle dernière édition sur ce point)
Mehdi LAMRANI
Pour un cas concret illustrant pourquoi je dois faire cela, vous pouvez jeter un oeil à mon dernier commentaire à JNK au bas de la question
Mehdi LAMRANI
4

C'est malheureusement par conception, veuillez faire référence à ce post. Cependant, dans ce post, il vous donne des instructions sur la façon de le contrôler.

/server/251832/sql-server-bulk-insert-physical-memory-issue

Modification de l'allocation de mémoire

La mémoire n'est pas freedactive car elle alloue beaucoup de mémoire comme une application .NET. Étant donné que l'allocation de mémoire est coûteuse, elle conservera cette allocation à moins que le système d'exploitation ne le demande. Mais n'ayez crainte, si le système d'exploitation veut la mémoire, il l'obtiendra, tout comme il le fait dans une application .NET.

Mike Perrenoud
la source
@MikaJacobi Bien sûr, pas de problème. Une autre chose à noter, juste pour que vous le sachiez, SQL Server prendra également en charge tous les cœurs, alors assurez-vous de limiter le nombre de cœurs disponibles. J'ai déjà vu SQL Server détruire le système d'exploitation sur lequel il fonctionne et j'ai dû redémarrer en dur un centre de données SQL Server.
Bon à savoir. J'ai 24 cœurs, donc ça va pour le moment. Mais pourquoi la mémoire n'est-elle pas libérée une fois l'insertion en bloc terminée?
Tant que l'insertion en bloc est terminée, si le système d'exploitation a besoin de la mémoire, elle lui sera donnée, mais il alloue beaucoup de mémoire comme une application .NET afin que s'il en a besoin et que personne d'autre ne puisse y accéder plus rapidement.
Mon expérience de hads-on contredit cela (voir la dernière édition).
Mehdi LAMRANI