# Limiter les ressources d'un login avec le Resource Governor

> Brider CPU, mémoire, I/O, concurrence et tempdb d'un login en lecture seule avec le Resource Governor, mesuré sur SQL Server 2022 et 2025.
>
> Source : https://www.pachadata.com/docs/howtos/performances/resource-governor-login-client/
> Auteur : Rudi Bruchez · publié le 2026-09-23 · mis à jour le 2026-10-19
> Version Markdown de la page, pour les outils et les LLM. La page HTML fait référence.


> TL;DR :
>
> Le Resource Governor place les sessions d'un login dans un groupe dont on plafonne le CPU, la mémoire de travail, les I/O, le nombre de requêtes simultanées et, depuis SQL Server 2025, l'espace occupé dans les fichiers de données de tempdb.
> Il est disponible en édition Enterprise, et en édition Standard depuis SQL Server 2025.
> Les réglages se font en T-SQL : la fenêtre de propriétés de SSMS n'expose pas le plafond CPU dur ni les I/O.


Le cas est fréquent chez les éditeurs qui hébergent la base de leurs clients.
On veut leur ouvrir un accès en lecture seule, pour quelques requêtes ou un tableau de bord, sans qu'ils y branchent un outil de reporting de production qui ferait tourner le serveur pour eux.
S'ils ont besoin de plus, ils passent à une offre avec un serveur dédié.

SQL Server ne sait pas limiter un utilisateur en nombre de requêtes par jour.
Ce qu'il sait faire, c'est reconnaître une session au moment de la connexion, par son login, le nom du poste ou le nom de l'application, et la placer dans un espace où ses ressources sont plafonnées.
C'est le rôle du [Resource Governor](https://learn.microsoft.com/en-us/sql/relational-databases/resource-governor/resource-governor).

Tous les exemples de cette page s'exécutent sur la base de démonstration `PachaDataFormation`.
Les mesures ont été faites sur deux conteneurs, SQL Server 2022 Developer (16.0.4265.3) et SQL Server 2025 Enterprise Developer (17.0.4065.4), avec 22 cœurs visibles.
L'édition Standard a été mesurée sur un troisième conteneur, SQL Server 2025 Standard Developer (17.0.4065.4) limité à 8 processeurs, avec la même base.

## Éditions et versions

Jusqu'à SQL Server 2022, le Resource Governor est réservé à l'édition Enterprise (et à l'édition Developer, qui en a les fonctionnalités).
Depuis SQL Server 2025, il est aussi disponible en édition Standard, [avec les mêmes fonctionnalités qu'en édition Enterprise](https://learn.microsoft.com/en-us/sql/sql-server/what-s-new-in-sql-server-2025) selon Microsoft.
L'édition Express n'y a pas droit.

La [page des éditions pour Linux](https://learn.microsoft.com/en-us/sql/linux/sql-server-linux-editions-and-components-2025) indique pourtant que la gouvernance des I/O reste réservée à l'édition Enterprise.
Sur notre conteneur Linux SQL Server 2025 en édition Standard Developer, la limite d'IOPS s'applique exactement comme en édition Enterprise : le parcours à froid mesuré plus bas y prend 2,4 s sans limite, 4,3 s à 100 IOPS et 20,7 s à 20 IOPS, contre 2,5, 4,2 et 20,0 s en édition Enterprise.

## Le login en lecture seule

On commence par le login lui-même, avec le seul droit de lire.
Remplacez le mot de passe de l'exemple.

```sql
USE [master];
GO
CREATE LOGIN [client_lecture] WITH PASSWORD = N'Chang3r-Ce-M0t-De-Passe!', CHECK_POLICY = ON;
GO
USE [PachaDataFormation];
GO
CREATE USER [client_lecture] FOR LOGIN [client_lecture];
ALTER ROLE [db_datareader] ADD MEMBER [client_lecture];
GO
```

Avec le seul rôle `db_datareader`, ce login ne peut pas modifier les tables, mais rien ne l'empêche de consommer.
Il peut lancer une jointure qui occupe plusieurs cœurs, un tri qui demande des centaines de mégaoctets, ou remplir tempdb : sur SQL Server 2022, il a copié sans difficulté le million de lignes de `Contact.ProspectUS` dans une table temporaire avec un `SELECT ... INTO #copie`.
C'est ce que le Resource Governor va encadrer.

## Le pool de ressources

Un pool de ressources est une part du serveur : CPU, mémoire de travail des requêtes, I/O.
Toutes les sessions qu'on y place se partagent cette part.

```sql
USE [master];
GO
CREATE RESOURCE POOL [pool_clients]
WITH (
    CAP_CPU_PERCENT = 10,
    MAX_MEMORY_PERCENT = 10,
    MAX_IOPS_PER_VOLUME = 100
);
GO
```

### CPU

`MAX_CPU_PERCENT` ne s'applique [qu'en cas de contention](https://learn.microsoft.com/en-us/sql/relational-databases/resource-governor/resource-governor-resource-pool) avec d'autres pools : si le serveur est calme, le pool peut prendre tout le CPU.
`CAP_CPU_PERCENT` est un plafond dur, appliqué même quand le serveur n'a rien d'autre à faire.
Pour des clients qu'on veut brider, c'est `CAP_CPU_PERCENT` qu'il faut.

La documentation ne dit pas sur quoi porte le pourcentage. Nos mesures montrent qu'il porte sur le CPU de toute l'instance, pas sur un cœur.
Sur nos 22 cœurs, 10 % représentent un peu plus de deux cœurs.
Une requête limitée à un seul thread n'utilise qu'environ 4,5 % de la machine : un plafond de 10 % ne la ralentit guère, 18,3 secondes contre 17,8 pour `sa` en série.
À 2 %, soit 0,44 cœur, la même requête passe de 18,3 à 43,4 secondes : 2,4 fois plus, proche de ce que donne le calcul (4,5 % divisé par 2 %, soit 2,25).
Calculez donc le pourcentage à partir du nombre de cœurs : sur un serveur de 16 cœurs, un cœur représente 6,25 %.

Microsoft précise que la régulation du CPU est statistique : [de courts pics au-dessus de la limite](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-resource-pool-transact-sql) restent possibles, et des requêtes très courtes peuvent [ne pas consommer assez longtemps](https://learn.microsoft.com/en-us/sql/relational-databases/resource-governor/resource-governor) pour être régulées.

### Mémoire

`MAX_MEMORY_PERCENT` ne limite pas la mémoire au sens large.
Il limite la mémoire de travail des requêtes, celle qu'elles réservent pour trier ou construire des tables de hachage.
Le [buffer pool](https://learn.microsoft.com/en-us/sql/relational-databases/resource-governor/resource-governor-resource-pool), qui garde les pages de données en cache, reste partagé entre tous les pools : un client qui lit une grosse table peut toujours en évincer les pages des autres applications.

À 10 %, le pool disposait sur notre instance SQL Server 2025, dont la mémoire maximale est de 4 Go, d'environ 390 Mo de mémoire de travail.
Une requête seule peut en prendre 25 % par défaut (réglage du groupe, plus bas), calculés sur la mémoire que le pool peut réellement accorder : 73 Mo pour la requête mesurée plus bas.

### I/O

`MAX_IOPS_PER_VOLUME` limite le nombre d'opérations d'entrées-sorties par seconde et par volume disque.
Ce n'est pas un débit : les lectures anticipées de SQL Server font souvent plusieurs centaines de kilo-octets.
Dans notre test, un parcours de table à froid a lu 192 Mo en 393 à 399 opérations selon les essais, soit près de 500 Ko chacune.

La limite porte sur les I/O physiques des requêtes, [lectures et écritures](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-resource-pool-transact-sql).
Une table déjà en cache se lit sans aucune I/O, donc sans ralentissement.
Les écritures du journal, du checkpoint et du lazy writer ne sont pas [gouvernées non plus](https://learn.microsoft.com/en-us/sql/relational-databases/resource-governor/resource-governor).
En revanche, les écritures et relectures dans tempdb d'un tri qui déborde le sont, et c'est ce qui rend ce réglage efficace (voir les mesures plus bas).

> Note :
>
> La limite d'IOPS n'apparaît pas dans l'interface de SSMS.
> Elle existe bien, elle se règle en T-SQL avec `MAX_IOPS_PER_VOLUME` dans `CREATE RESOURCE POOL` ou `ALTER RESOURCE POOL`.


## Le groupe de charge de travail

Les sessions ne sont pas placées directement dans un pool, mais dans un groupe de charge de travail (*workload group*) rattaché à un pool.
Le groupe porte les limites qui s'appliquent requête par requête.

```sql
USE [master];
GO
CREATE WORKLOAD GROUP [groupe_clients]
WITH (
    GROUP_MAX_REQUESTS = 2,
    MAX_DOP = 1,
    REQUEST_MAX_MEMORY_GRANT_PERCENT = 25,
    REQUEST_MAX_CPU_TIME_SEC = 60
)
USING [pool_clients];
GO
```

`GROUP_MAX_REQUESTS` fixe le nombre de requêtes qui s'exécutent en même temps dans le groupe.
Au-delà, la requête [attend son tour](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-workload-group-transact-sql), sans erreur.
Son effet se prévoit facilement : avec 2, un outil qui ouvre dix connexions n'en fait jamais travailler que deux.

`MAX_DOP` limite le parallélisme de chaque requête du groupe.
Il l'emporte sur l'option d'instance `max degree of parallelism` et sur la configuration de base, et un indicateur `OPTION (MAXDOP n)` n'est respecté que s'il ne dépasse pas cette valeur.
Avec `MAX_DOP = 1` et `GROUP_MAX_REQUESTS = 2`, le client n'occupe jamais plus de deux cœurs, quel que soit le plafond CPU du pool.

`REQUEST_MAX_MEMORY_GRANT_PERCENT` est la part de la mémoire du pool qu'une seule requête peut réserver.
25 est la valeur par défaut, l'écrire rend simplement le réglage visible.
Dans un groupe créé par l'utilisateur, une requête dont le besoin minimal de mémoire dépasse ce plafond voit d'abord son parallélisme réduit, puis [échoue avec l'erreur 8657](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-workload-group-transact-sql) : ne descendez pas ce réglage trop bas, ni la mémoire du pool.

Le nom de `REQUEST_MAX_CPU_TIME_SEC` laisse croire qu'il arrête la requête.
Par défaut, une requête qui dépasse ce temps CPU n'est pas arrêtée : SQL Server déclenche l'événement étendu `cpu_threshold_exceeded` et incrémente le compteur `total_cpu_limit_violation_count`, puis la laisse finir.
Pour qu'elle soit annulée, il faut activer le trace flag global 2422.
La requête reçoit alors l'erreur 10961.
Ce trace flag vaut pour tous les groupes de l'instance.

```sql
DBCC TRACEON (2422, -1);
```

`DBCC TRACEON` ne survit pas à un redémarrage.
Pour le rendre permanent, ajoutez `-T2422` aux paramètres de démarrage dans le Gestionnaire de configuration SQL Server, ou, sous Linux, `sudo /opt/mssql/bin/mssql-conf traceflag 2422 on` puis un redémarrage du service.

Le temps CPU n'est vérifié [que toutes les cinq secondes](https://learn.microsoft.com/en-us/sql/t-sql/statements/create-workload-group-transact-sql). Pour cette mesure, la requête tournait dans un groupe en `MAX_DOP = 1`, rattaché à un pool sans plafond CPU ni limite de mémoire ou d'I/O (`CAP_CPU_PERCENT = 100`, `MAX_MEMORY_PERCENT = 100`, `MAX_IOPS_PER_VOLUME = 0`), pour que son temps CPU suive le temps écoulé. Avec une limite de 2 secondes et le trace flag, notre requête en série a été annulée après 3,7 à 5,1 secondes de CPU, soit 3,8 à 5,3 secondes écoulées. Une requête de 3,5 secondes de CPU est passée les trois fois, une de 4,8 secondes une fois sur trois. Sans le trace flag, la détection est aussi irrégulière : une requête de 6,2 secondes de CPU a été comptée dans `total_cpu_limit_violation_count`, une de 7,7 secondes ne l'a pas été.

### tempdb, depuis SQL Server 2025

SQL Server 2025 ajoute une limite sur l'espace qu'un groupe occupe dans les fichiers de données de tempdb : tables temporaires, variables table, débordements de tris et de hachages.
Le version store n'est pas compté, ni le journal de tempdb : pour contenir celui-ci, Microsoft conseille d'activer ADR (*accelerated database recovery*) dans tempdb.

```sql
USE [master];
GO
ALTER WORKLOAD GROUP [groupe_clients] WITH (GROUP_MAX_TEMPDB_DATA_MB = 512);
GO
```

Au dépassement, la requête est annulée avec l'erreur 1138, `Could not allocate a new page for database 'tempdb' because that would exceed the limit set for workload group`.
Il existe aussi `GROUP_MAX_TEMPDB_DATA_PERCENT`, mais il [ne s'applique pas](https://learn.microsoft.com/en-us/sql/relational-databases/resource-governor/tempdb-space-resource-governance) sur une installation par défaut, dont les fichiers tempdb ont une taille maximale illimitée et une croissance automatique : la limite en mégaoctets est plus simple.
SQL Server 2022 refuse cette option avec une erreur de syntaxe.

## La fonction de classification

Reste à dire au Resource Governor quelles sessions vont dans `groupe_clients`.
C'est le travail d'une fonction de classification, appelée à chaque nouvelle connexion, qui renvoie le nom du groupe.
Elle doit être créée dans `master`, avec `SCHEMABINDING`.

```sql
USE [master];
GO
CREATE FUNCTION dbo.fn_classification_rg()
RETURNS sysname
WITH SCHEMABINDING
AS
BEGIN
    RETURN CASE WHEN SUSER_SNAME() = N'client_lecture'
                THEN N'groupe_clients'
                ELSE N'default'
           END;
END;
GO
ALTER RESOURCE GOVERNOR WITH (CLASSIFIER_FUNCTION = dbo.fn_classification_rg);
ALTER RESOURCE GOVERNOR RECONFIGURE;
GO
```

`ALTER RESOURCE GOVERNOR RECONFIGURE` active le Resource Governor, désactivé à l'installation, et applique la configuration.
Il faut le relancer après chaque modification d'un pool ou d'un groupe.

Le login est le critère le plus sûr, parce que SQL Server l'a authentifié.
La fonction peut aussi classer sur le nom du poste client, `HOST_NAME()`, ou sur le nom de l'application, `APP_NAME()`, par exemple pour brider un outil précis quel que soit le compte utilisé :

```sql
USE [master];
GO
ALTER RESOURCE GOVERNOR WITH (CLASSIFIER_FUNCTION = NULL);
ALTER RESOURCE GOVERNOR RECONFIGURE;
GO
ALTER FUNCTION dbo.fn_classification_rg()
RETURNS sysname
WITH SCHEMABINDING
AS
BEGIN
    RETURN CASE
               WHEN SUSER_SNAME() = N'client_lecture' THEN N'groupe_clients'
               WHEN HOST_NAME() = N'POSTE-BI-01' THEN N'groupe_clients'
               WHEN APP_NAME() LIKE N'Microsoft Office%' THEN N'groupe_clients'
               ELSE N'default'
           END;
END;
GO
ALTER RESOURCE GOVERNOR WITH (CLASSIFIER_FUNCTION = dbo.fn_classification_rg);
ALTER RESOURCE GOVERNOR RECONFIGURE;
GO
```

Ces deux valeurs sont déclarées par le client dans sa chaîne de connexion, et rien ne les vérifie.
Elles servent à ranger des applications de bonne foi. Quelqu'un qui veut contourner la limite n'a qu'à annoncer un autre nom.
L'inverse est vrai aussi : dans notre test, une session `sa` ouverte avec le nom de poste `POSTE-BI-01` s'est retrouvée dans `groupe_clients`.

Le début de ce script détache la fonction, parce qu'une fonction de classification active ne peut être ni modifiée ni supprimée (erreur 10920).
Entre les deux `RECONFIGURE`, les nouvelles connexions vont dans le groupe `default`.

Quelques règles pour cette fonction :

- elle s'exécute à chaque connexion, avant que la session soit utilisable : gardez-la simple, sans lecture de table si possible, sinon les connexions ralentissent ou expirent ;
- si elle renvoie `NULL`, le nom d'un groupe qui n'existe pas, ou si elle échoue, la session va dans `default` ;
- elle classe la session pour toute sa durée : une session ouverte avant l'activation reste dans son groupe. Microsoft précise que la fonction est évaluée pour chaque nouvelle session, même avec un pool de connexions.

## Vérifier la classification

Connectez-vous avec `client_lecture`, puis, depuis une session d'administrateur :

```sql
SELECT s.session_id,
       s.login_name,
       s.host_name,
       s.program_name,
       g.name AS groupe,
       p.name AS pool
FROM sys.dm_exec_sessions AS s
JOIN sys.dm_resource_governor_workload_groups AS g ON g.group_id = s.group_id
JOIN sys.dm_resource_governor_resource_pools AS p ON p.pool_id = g.pool_id
WHERE s.is_user_process = 1;
```

Lancée par `client_lecture`, cette requête échoue : les vues du Resource Governor demandent la permission `VIEW SERVER PERFORMANCE STATE`, dont il n'a pas besoin.

## SSMS ou T-SQL

Dans SSMS, le Resource Governor se trouve dans l'Explorateur d'objets, sous Gestion (*Management*), puis Resource Governor.
Tant qu'il est désactivé, son icône porte une croix rouge.

![Le nœud Resource Governor déplié dans l'Explorateur d'objets de SSMS, sous Management, avec les dossiers Resource Pools et External Resource Pools](./explorateur-objets-resource-governor.png)

Un clic droit sur ce nœud propose la création d'un pool.

![Menu contextuel du nœud Resource Governor : New Resource Pool et New External Resource Pool](./menu-nouveau-pool.png)

Sa [fenêtre de propriétés](https://learn.microsoft.com/en-us/sql/relational-databases/resource-governor/view-resource-governor-properties) permet de créer des pools et des groupes.
Pour les groupes, elle expose le nombre de requêtes simultanées, le temps CPU, la part de mémoire et le degré de parallélisme.
Pour les pools, elle ne propose que les pourcentages minimum et maximum de CPU et de mémoire : le plafond dur `CAP_CPU_PERCENT`, les IOPS et la limite tempdb n'y figurent pas.

![Fenêtre de propriétés du Resource Governor sur une instance neuve : grille des pools default et internal, grille des groupes de charge de travail](./proprietes-resource-governor.png)

La fonction de classification s'écrit aussi en T-SQL, la fenêtre ne fait que la choisir dans une liste.
Sur une instance où aucune fonction n'a été créée, cette liste ne propose que `None`.

![Liste déroulante Classifier function name de la fenêtre de propriétés, qui ne propose que None](./proprietes-fonction-classification.png)

Autant tout faire dans une fenêtre de requête SSMS, connectée à l'instance avec un compte qui a la permission `CONTROL SERVER`.
Le T-SQL a un autre avantage : la configuration vit dans `master`, et un script se rejoue sur un autre serveur ou après une reconstruction.

## Ce que le client constate

Pour mesurer l'effet de chaque réglage, nous avons lancé la même requête avec `sa` et avec `client_lecture`.
Elle cherche les homonymes qui habitent des villes différentes :

```sql
USE [PachaDataFormation];
GO
SELECT COUNT_BIG(*) AS homonymes
FROM Contact.ProspectUS AS a
JOIN Contact.ProspectUS AS b ON b.Nom = a.Nom AND b.Ville <> a.Ville;
```

Temps écoulés sur SQL Server 2025 en édition Enterprise Developer, avec la configuration du script ci-dessus sauf mention contraire, dans une même série, médiane de trois exécutions (une seule pour la ligne des requêtes simultanées).
`PachaDataFormation` est réglée en `MAXDOP = 2` au niveau de la base (`ALTER DATABASE SCOPED CONFIGURATION`) : c'est le parallélisme de `sa` et du client en `MAX_DOP = 0`.
Sur 2022, le plafond de 2 % donne le même ordre de grandeur : 42,5 secondes.
En édition Standard, la même requête prend 27,0 secondes pour `sa` en parallèle et 53,8 en série, environ trois fois plus qu'en édition Enterprise, parce que son plan reste en mode ligne : le [mode batch sur des tables rowstore](https://learn.microsoft.com/en-us/sql/sql-server/editions-and-components-of-sql-server-2025), que l'optimiseur choisit ici en édition Enterprise, est réservé à celle-ci.
Le Resource Governor y agit de la même façon : 27,1 secondes en `MAX_DOP = 0` à 10 %, 54,9 en `MAX_DOP = 1`, 139,7 à 2 %.

| Situation | Temps écoulé |
|---|---|
| `sa`, sans limite, en parallèle | 8,3 s |
| `client_lecture`, `MAX_DOP = 0`, `CAP_CPU_PERCENT = 10` | 11,1 s |
| `client_lecture`, `MAX_DOP = 1`, `CAP_CPU_PERCENT = 10` | 18,3 s |
| `client_lecture`, `MAX_DOP = 1`, `CAP_CPU_PERCENT = 2` | 43,4 s |
| trois requêtes simultanées avec `GROUP_MAX_REQUESTS = 2` : la troisième | 39,8 s |

À 10 %, le client en `MAX_DOP = 0` garde ses deux threads et perd 2,8 secondes.
Le plafond CPU ne les explique pas : porté à 100 %, il laisse le temps presque inchangé, 11,4 secondes.
Ils viennent de la mémoire et de la limite d'I/O du pool.
`MAX_MEMORY_PERCENT = 10` limite l'allocation de la requête à 73 Mo, quand elle en obtient 224 pour `sa`.
La jointure par hachage déborde alors dans tempdb, environ 2 250 pages écrites puis relues, et ces quelque 330 écritures et 330 lectures passent par la limite de 100 IOPS : la session attend 6,3 à 6,8 secondes en `SLEEP_TASK`, réparties sur ses deux threads (relevé dans une série d'analyse, avec le plan réel).
Sans limite de mémoire ni d'I/O, sous le plafond de 10 %, le client met 8,8 secondes, près du temps de `sa` ; avec le débordement mais sans limite d'I/O, 7,7 secondes.
Avec `MAX_DOP = 1`, le client perd le parallélisme.
Quand un outil multiplie les requêtes, `GROUP_MAX_REQUESTS` se fait sentir : la troisième attend que l'une des deux premières se termine.
Pendant cette attente, `sys.dm_resource_governor_workload_groups` montre `active_request_count = 2` et `queued_request_count = 1`.
Le temps passé dans la file n'apparaît pas dans `SET STATISTICS TIME`, qui ne compte que l'exécution : mesurez-le côté client.

Pour les I/O, un parcours de `Contact.ProspectUS_N` après vidage du cache (`CHECKPOINT` puis `DBCC DROPCLEANBUFFERS`, à ne pas lancer en production ; nos mesures partaient d'une copie de la base fraîchement restaurée), soit 393 à 399 lectures selon les essais, sur SQL Server 2025 :

```sql
USE [PachaDataFormation];
GO
SELECT COUNT_BIG(*) AS nb
FROM Contact.ProspectUS_N
WHERE Email LIKE N'%@gmail%';
```

| `MAX_IOPS_PER_VOLUME` | Temps écoulé |
|---|---|
| 0 (pas de limite) | 2,5 s |
| 100 | 4,2 s |
| 20 | 20,0 s |

Les limites se combinent.
Avec `MAX_MEMORY_PERCENT = 1`, les autres réglages inchangés, un tri de `Contact.ProspectUS_N` n'obtient plus que 12 Mo de mémoire et déborde dans tempdb :

```sql
USE [PachaDataFormation];
GO
SELECT COUNT_BIG(*) AS echantillon
FROM (SELECT Email,
             ROW_NUMBER() OVER (ORDER BY Email, Nom, Prenom, Adresse) AS rn
      FROM Contact.ProspectUS_N) AS t
WHERE rn % 1000 = 0;
```

Sans limite d'I/O, la requête met 11 secondes, en série, sous le plafond CPU de 10 % et avec son débordement.
Avec `MAX_IOPS_PER_VOLUME = 100`, ses quelque 13 100 écritures et 13 100 relectures dans tempdb passent par la limite d'IOPS, et la requête met 266 secondes, près de quatre minutes et demie.
La même requête prend 2,4 secondes pour `sa`.
Le groupe a occupé au plus 142 Mo de tempdb, sous la limite de 512 Mo posée plus haut : pas d'erreur 1138. Mesures sur SQL Server 2025.

## Suivre la consommation et ajuster

`sys.dm_resource_governor_workload_groups` et `sys.dm_resource_governor_resource_pools` tiennent des compteurs cumulés par groupe et par pool :

```sql
SELECT g.name,
       g.statistics_start_time,
       g.total_request_count,
       g.total_queued_request_count,
       g.total_cpu_usage_ms,
       g.total_cpu_limit_violation_count,
       g.total_reduced_memgrant_count,
       g.max_request_grant_memory_kb,
       p.read_io_completed_total,
       p.read_io_throttled_total,
       p.write_io_throttled_total
FROM sys.dm_resource_governor_workload_groups AS g
JOIN sys.dm_resource_governor_resource_pools AS p ON p.pool_id = g.pool_id
WHERE g.name = N'groupe_clients';
```

Ils partent du dernier démarrage de l'instance ou de la dernière remise à zéro, dont `statistics_start_time` donne la date :

```sql
ALTER RESOURCE GOVERNOR RESET STATISTICS;
```

Cette commande remet à zéro les compteurs de tous les groupes et de tous les pools de l'instance.

`total_queued_request_count` et les compteurs `*_throttled_total` disent si le client bute sur les limites.
`total_cpu_usage_ms` donne sa consommation réelle.
`total_request_count` compte les requêtes terminées, c'est-à-dire les lots envoyés au serveur, et non des requêtes métier : une connexion `sqlcmd` qui exécute un simple `SELECT 1;` l'augmente de 3, parce que `sqlcmd` envoie deux lots `SET QUOTED_IDENTIFIER` et `SET TEXTSIZE` avant la requête.
Sur SQL Server 2025, `peak_tempdb_data_space_kb` et `total_tempdb_data_limit_violation_count` couvrent tempdb.

Relevés de temps en temps, ces chiffres suffisent pour ajuster les limites, ou pour montrer au client ce qu'il consomme.

## Modifier la configuration en production

Une modification du plafond CPU d'un pool, validée par `ALTER RESOURCE GOVERNOR RECONFIGURE`, s'applique aussi aux requêtes en cours.
Nous avons lancé la requête des homonymes avec `CAP_CPU_PERCENT = 2`, puis relevé le plafond à 100 au bout de trois secondes : elle s'est terminée en 20,0 secondes au lieu de 43,4, ce qui correspond à un changement immédiat.
Le degré de parallélisme, lui, est fixé au démarrage de chaque requête.
Passer `MAX_DOP` à 1 s'applique aussi aux plans déjà en cache, qui s'exécutent alors en série.
Dans l'autre sens, un plan compilé en série le reste : pour que les requêtes du groupe profitent d'une valeur plus haute, videz le cache du pool avec `DBCC FREEPROCCACHE ('pool_clients')`, comme l'indique la [documentation](https://learn.microsoft.com/en-us/sql/t-sql/statements/alter-workload-group-transact-sql).

```sql
USE [master];
GO
ALTER RESOURCE POOL [pool_clients] WITH (CAP_CPU_PERCENT = 5);
ALTER RESOURCE GOVERNOR RECONFIGURE;
GO
```

Deux précautions :

- rattacher un groupe à un autre pool [échoue](https://learn.microsoft.com/en-us/sql/relational-databases/resource-governor/move-a-workload-group) tant que le groupe a des sessions ouvertes ;
- si une fonction de classification défectueuse empêche les connexions, la connexion administrateur dédiée (DAC, `ADMIN:` devant le nom du serveur) n'est pas classée et permet de la détacher. Par défaut, elle n'accepte que les connexions depuis le serveur lui-même ; à distance, il faut avoir activé l'option `remote admin connections` au préalable.

La configuration est stockée dans `master`.
Dans un groupe de disponibilité, elle ne se réplique pas : rejouez le script sur chaque réplica.

## Revenir en arrière

Pour tout supprimer, fermez d'abord les sessions de `client_lecture` : un groupe qui a des sessions ouvertes ne se supprime pas, et un login connecté non plus.

```sql
USE [master];
GO
ALTER RESOURCE GOVERNOR WITH (CLASSIFIER_FUNCTION = NULL);
ALTER RESOURCE GOVERNOR RECONFIGURE;
GO
DROP FUNCTION dbo.fn_classification_rg;
DROP WORKLOAD GROUP [groupe_clients];
DROP RESOURCE POOL [pool_clients];
ALTER RESOURCE GOVERNOR RECONFIGURE;
GO
USE [PachaDataFormation];
GO
DROP USER [client_lecture];
GO
USE [master];
GO
DROP LOGIN [client_lecture];
GO
```

Si vous avez activé le trace flag 2422, désactivez-le avec `DBCC TRACEOFF (2422, -1);`, et retirez `-T2422` des paramètres de démarrage, ou, sous Linux, lancez `sudo /opt/mssql/bin/mssql-conf traceflag 2422 off`.

Le Resource Governor reste activé, sans autre effet que de placer toutes les sessions dans `default`.
`ALTER RESOURCE GOVERNOR DISABLE;` le ramène à son état d'installation.


---

## L'auteur

Rudi Bruchez, consultant SQL Server indépendant depuis 2006 : audit de performance, optimisation, migrations, haute disponibilité et formation. Pour un audit ou une intervention sur votre serveur : https://www.pachadata.com/contact/ (audit à distance : https://www.pachadata.com/services/audit-sql-server-a-distance/).
