Nous sommes sur SQL Server 2012 SP3 Enterprise Edition sur Windows 2012 R2.
J'ai vu ces erreurs dans les journaux sql:
Échec de l'allocation des pages: FAIL_PAGE_ALLOCATION 1
2016-06-14 04: 28: 27.44 spid175 Erreur: 701, gravité: 17, état: 123.
2016-06-14 04: 28: 27.44 spid175 La mémoire système du pool de ressources "par défaut" est insuffisante pour exécuter cette requête.
2016-06-14 04: 28: 27.44 Erreur de serveur: 17300, gravité: 16, état: 1. (Paramètres :). L'erreur est imprimée en mode laconique car une erreur s'est produite lors du formatage. Le traçage, l'ETW, les notifications, etc. sont ignorés.
2016-06-14 04: 28: 27.44 Erreur de serveur: 17300, gravité: 16, état: 1. (Paramètres :). L'erreur est imprimée en mode laconique car une erreur s'est produite lors du formatage. Le traçage, l'ETW, les notifications, etc. sont ignorés.
2016-06-14 04: 28: 27.44 spid131 Erreur: 701, gravité: 17, état: 123.
Pour autant que je sache, il semble qu'il y ait eu un manque de mémoire à un moment donné.
Existe-t-il un moyen de comprendre ce qui a causé sa perte de mémoire?
Le MEMORYCLERK_SQLQERESERVATIONS
est assez élevé, est-ce que quelqu'un sait à quoi ça sert?
MEMORYCLERK_SQLQERESERVATIONS (node 0) KB
---------------------------------------- ----------
VM Reserved 0
VM Committed 0
Locked Pages Allocated 0
SM Reserved 0
SM Committed 0
Pages Allocated 22599824
EDIT: Nous avons 32 concerts de RAM sur le serveur et 28 sont alloués au serveur SQL. Le paramètre de mémoire maximale est de 28 Go et la mémoire minimale du serveur est de 8 Go.
Voici un lien vers la sortie ErrorLog: ErrorLog
Voici le lien vers la sortie sys.dm_os_process_memory: Query Output
Lien vers les types d'attente: WaitTypes
Je l'ai exécuté pendant une période où nous semblons avoir plus d'utilisation de la mémoire:
SELECT * FROM sys.dm_exec_query_memory_grants où grant_time est null
Résultats: memory_grants
SELECT mg.granted_memory_kb, mg.session_id, t.text, qp.query_plan FROM sys.dm_exec_query_memory_grants AS mg CROSS APPLY sys.dm_exec_sql_text (mg.sql_handle) AS t CROSS APPLY sys.dm_exec_query_planDER) OPTION (MAXDOP 1) Résultats: QueryMemGrants
SELECT top 50 t.text, cp.objtype, qp.query_plan, cp.usecounts, cp.size_in_bytes> as [Bytes Used in Cache] FROM sys.dm_exec_cached_plans AS cp JOIN sys.dm_exec_query_stats AS qs ON cp.plan_handle = qs.plan_hand CROSS APPLY sys.dm_exec_query_plan (cp.plan_handle) AS qp CROSS APPLY sys.dm_exec_sql_text (qs.sql_handle) AS t WHERE qp.query_plan.exist ('declare namespace> n = "http://schemas.Microsoft.com/sqlserver/ 2004/07/showplan ";> // n: MemoryFractions ') = 1 ordre par cp.size_in_bytes desc OPTION (MAXDOP 1)
Résultats: CachedMemGrants
Sélectionnez grant_query_memory, session_id, command from sys.dm_exec_requests Résultats: dm_exec_requests
XML du plan de requête de l'une des requêtes en cours d'exécution: QueryPlan
La sortie de errorlog avait dbcc memorystatus
vidage et ce que j'ai remarqué était
Process/System Counts Value(in Bytes)
---------------------------------------- ----------
Available Physical Memory 1217605632---1.1 G
Available Virtual Memory 140627167866880
Available Paging File 5656502272
Working Set 305238016
Percent of Committed Memory in WS 99
Page Faults 27923310
System physical memory high 0
System physical memory low 0
Process physical memory low 1--Memory Low
Process virtual memory low 0
2016-06-14 04:28:27.41 Server
Veuillez noter que la mémoire physique disponible est très faible. Il n'y avait presque pas de mémoire dans le pool de tampons
Concernant l'employé qui consomme plus de mémoire
MEMORYCLERK_SQLQERESERVATIONS (node 0) KB
---------------------------------------- ----------
VM Reserved 0
VM Committed 0
Locked Pages Allocated 0
SM Reserved 0
SM Committed 0
Pages Allocated 22599824 --21.5 G
Page Life Expectancy 64
Maintenant sur le serveur où la mémoire maximale du serveur est de 28 G si MEMORYCLERK_SQLQERESERVATIONS
prend 21,5 G, ce qui est certainement un problème. C'est ce qui cause la condition OOM.
Qu'est-ce que MEMORYCLERK_SQLQERESERVATIONS
Il s'agit d'un commis de mémoire dans SQL Server qui suit la mémoire allouée à la requête qui implique Trier ou opérations de hachage pendant l'exécution. Ces opérateurs peuvent être les plus grands consommateurs de mémoire pour une requête.
Pourquoi une erreur OOM à cause de cela
Lorsque la requête impliquant des opérations de tri et de hachage est exécutée, elle fera une demande de réservation basée sur le plan de requête d'origine qui contenait un opérateur de tri ou de hachage. Ensuite, au fur et à mesure que la requête s'exécute, elle demande de la mémoire et SQL Server accordera cette demande partiellement ou entièrement en fonction de la disponibilité de la mémoire. Un commis à la mémoire (comptable) nommé "MEMORYCLERK_SQLQERESERVATIONS" assure le suivi de l’allocation de mémoire à ces demandes. Maintenant, dans votre scénario, cela pourrait se produire
La requête demande tellement d'allocation de mémoire que SQL Server ne peut lui fournir qu'une quantité limitée, cette quantité limitée est appelée "mémoire requise", de sorte qu'elle commence à s'exécuter et pendant l'exécution de la requête, car la mémoire requise était importante et SQL Server ne peut pas fournissez-le car il n'y avait pas de mémoire dans le pool de ressources, la requête échoue avec une erreur OOM. La mémoire requise lors de l'exécution de la requête est appelée "Mémoire supplémentaire"
Un bug a été résolu dans SQL Server 2012 Sp1 CU4 où la requête demandait une énorme quantité d'allocation de mémoire, ce qui la ralentissait considérablement ou échouait par la suite avec une erreur OOM. La possibilité que le bogue refait surface ne peut être exclue étant donné que QEReservations a monopolisé tout le pool de tampons
Depuis le greffier a déjà pris 90% de la mémoire. La mémoire requise pour la nouvelle requête n'est pas disponible et la requête échoue avec une erreur MOO.
Vos tables et index ont des statistiques faussées, ce qui oblige l'optimiseur à créer un plan sous-optimal, ce qui lui fait demander beaucoup plus de mémoire que ce qui est réellement requis et, à son tour, créer des problèmes.
Enfin, les requêtes en cours d'exécution sur SQL Server nécessitent un réglage sérieux.
Selon ceci article Blogs.msdn
Que peut réellement faire un développeur à propos des opérations de tri/hachage?
En parlant de réécriture de requêtes, voici quelques éléments à rechercher dans une requête qui peuvent entraîner d'importantes allocations de mémoire.
Raisons pour lesquelles une requête utiliserait un opérateur SORT (liste non exhaustive):
ORDER BY (T-SQL) GROUP BY (T-SQL) DISTINCT (T-SQL) Merge Join operator selected by the optimizer and one of the inputs of the Merge join has to be sorted because a clustered index is
non disponible sur cette colonne.
Raisons pour lesquelles une requête utiliserait un opérateur Hash Match (liste non exhaustive):
JOIN (T-SQL) – if SQL ends up performing a Hash Join. Typically, lack of good indexes may lead to the most expensive of join operators
- Hash Join. Regardez le plan de requête.
DISTINCT (T-SQL) – a Hash Aggregate could be used to perform the distinct. Look at query plan. SUM/AVG/MAX/MIN (T-SQL)– any aggregate operation could potentially be performed as a Hash Aggregate . Look at query plan. UNION – a Hash Aggregate could be used to remove the duplicates.
Pour mieux comprendre le problème, je vous demanderais d'ajouter la sortie des requêtes ci-dessous dans votre question. J'aimerais également que vous ajoutiez la sortie de Paul Randal Wait stats query . La source de la requête est Ce blog , je vous suggère de lire le blog.
SELECT * FROM sys.dm_exec_query_memory_grants where grant_time is null
--Find who uses the most query memory grant:
SELECT mg.granted_memory_kb, mg.session_id, t.text, qp.query_plan
FROM sys.dm_exec_query_memory_grants AS mg
CROSS APPLY sys.dm_exec_sql_text(mg.sql_handle) AS t
CROSS APPLY sys.dm_exec_query_plan(mg.plan_handle) AS qp
ORDER BY 1 DESC OPTION (MAXDOP 1)
--Search cache for queries with memory grants:
SELECT t.text, cp.objtype,qp.query_plan
FROM sys.dm_exec_cached_plans AS cp
JOIN sys.dm_exec_query_stats AS qs ON cp.plan_handle = qs.plan_handle
CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) AS qp
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS t
WHERE qp.query_plan.exist(‘declare namespace n=”http://schemas.Microsoft.com/sqlserver/2004/07/showplan“; //n:MemoryFractions’) = 1
Il y a peu d'autres choses que j'aimerais que vous vérifiiez pour les requêtes en cours d'exécution sur le système.
Select granted_query_memory,session_id,command from sys.dm_exec_requests
Cela vous montrera combien de mémoire est accordée aux requêtes exécutées sur le système.
Si vous pouvez voir le plan d'exécution XML réel, vous avez MemoryGrant=xxxxx
pouvez-vous collecter cette valeur pour les requêtes coûteuses.
Tout ce qui précède nous montrera s'il y a un problème dans la requête ou un autre problème expliquant pourquoi il demande autant de mémoire pour l'exécution.
[~ # ~] modifier [~ # ~]
À partir de diverses sorties de requête que vous avez collées.
Tu peux voir le requested_memory_kb
pour un grand nombre de requêtes d'environ 5 G, il s'agit d'une allocation de mémoire importante, idéalement de quelques Mo. Notez que required_memory_kb
ne fait que 5 Mo environ et granted_query_memory
est NULL, car en raison de la pression de la mémoire, SQL Server est juste en mesure de fournir la mémoire minimale pour démarrer la requête, mais pas en mesure de fournir de la mémoire supplémentaire pour l'exécution de la requête, la requête échouant avec une erreur OOM.
Le coût des requêtes pour les requêtes demandant une mémoire énorme est également élevé, ce qui m'amène à croire que les statistiques sont biaisées ou que les requêtes sont mal écrites. Une autre possibilité serait une requête non prise en charge par un index approprié. Le nombre de requêtes demandant une telle allocation de mémoire est bon en nombre.
Pour les requêtes ci-dessus, voir granted_query_memory
tout est en Go. Les 3 premières requêtes exécutées ont utilisé environ 15 Go de mémoire, ce qui a presque utilisé 50% de la mémoire. Dans SQL Server, des millions de processus s'exécutent et nécessitent de la mémoire d'une manière ou d'une autre afin que vous puissiez voir si 3 requêtes utilisent 50% de la mémoire disponible.
Solution
Vous devriez sérieusement envisager de régler les 4 premières requêtes de la capture d'écran ci-dessus
Assurez-vous d'exécuter la reconstruction d'index et la mise à jour des statistiques au moins une fois par semaine afin que les statistiques asymétriques ne forcent pas l'optimiseur à produire un mauvais plan.
Utilisez le gouverneur de ressources et créez un pool de ressources et un groupe de charge de travail et exécutez des requêtes qui demandent une allocation de mémoire importante dans ce pool. Vous pouvez limiter la demande de mémoire avec le paramètre request_max_memory_grant_percentage
. Un exemple est montré dans ce blog . Il s'agit simplement d'une méthode alternative jusqu'à ce que vous régliez toutes vos requêtes.