Scénario: SQL Server 2014 (v12.0.4100.1)
Le service .NET exécute cette requête:
SELECT name, base_object_name
FROM sys.synonyms
WHERE schema_id IN (SELECT schema_id
FROM sys.schemas
WHERE name = N'XXXX')
ORDER BY name
... qui renvoie environ 6500 lignes, mais il arrive souvent à expiration après 3 minutes ou plus. Ce qui XXXX
précède n'est pas «dbo».
Si j'exécute cette requête dans SSMS en tant qu'utilisateurA, la requête retourne en moins d'une seconde.
Lorsqu'elle est exécutée en tant qu'utilisateurB (c'est ainsi que le service .NET se connecte), la requête prend 3 à 6 minutes et le CPU% à 25% (sur 4 cœurs) tout le temps.
UserA est une connexion de domaine dans le rôle sysadmin.
UserB est une connexion SQL avec:
EXEC sp_addrolemember N'db_datareader', N'UserB'
EXEC sp_addrolemember N'db_datawriter', N'UserB'
EXEC sp_addrolemember N'db_ddladmin', N'UserB'
GRANT EXECUTE TO [UserB]
GRANT CREATE SCHEMA TO [UserB]
GRANT VIEW DEFINITION TO [UserB]
Je peux dupliquer cela dans SSMS en enveloppant le SQL ci-dessus dans un Execute as...Revert
bloc, de sorte que le code .NET est hors de l'image.
Le plan d'exécution est identique. J'ai diff'ed le XML et il n'y a que des différences mineures (CompileTime, CompileCPU, CompileMemory).
Les statistiques d'E / S n'indiquent aucune lecture physique:
Table 'sysobjvalues'. Nombre de balayages 0, lectures logiques 19970, lectures physiques 0, lectures anticipées 0, lectures logiques 0, lob lectures physiques 0, lob lectures anticipées 0. Tableau «Fichier de travail». Nombre de balayages 0, lectures logiques 0, lectures physiques 0, lectures anticipées 0, lectures logiques 0, lob lectures physiques 0, lob lectures anticipées 0. Tableau «Table de travail». Nombre de balayages 0, lectures logiques 0, lectures physiques 0, lectures anticipées 0, lectures logiques 0, lob lectures physiques 0, lob lectures anticipées 0. Tableau «sysschobjs». Nombre de balayages 1, lectures logiques 9122, lectures physiques 0, lectures anticipées 0, lectures logiques 0, lob lectures physiques 0, lob lectures anticipées 0. Tableau 'sysclsobjs'. Nombre de balayages 0, lectures logiques 2, lectures physiques 0, lectures anticipées 0, lectures logiques 0, lob lectures physiques 0, lob lectures anticipées 0.
L'état d'attente de XEvent (pour une requête d'environ 3 minutes) est le suivant:
+ --------------------- + ------------ + -------------- -------- + ------------------------------ + ---------- ------------------- + | Type d'attente | Nombre d'attente | Temps d'attente total (ms) | Temps d'attente total des ressources (ms) | Temps d'attente total du signal (ms) | + --------------------- + ------------ + -------------- -------- + ------------------------------- + --------- -------------------- + | SOS_SCHEDULER_YIELD | 37300 | 427 | 20 | 407 | | NETWORK_IO | 5 | 26 | 26 | 0 | | IO_COMPLETION | 3 | 1 | 1 | 0 | + --------------------- + ------------ + -------------- -------- + ------------------------------- + --------- -------------------- +
Si je réécris la requête (dans SSMS, je n'ai pas accès au code d'application) pour
declare @id int
SELECT @id=schema_id FROM sys.schemas WHERE name = N'XXXX'
SELECT a.name, base_object_name FROM sys.synonyms a
WHERE schema_id = @id
ORDER BY name
puis UserB s'exécute à la même vitesse (rapide) que UserA.
Si j'ajoute db_owner
à UserB, alors, encore une fois, la requête s'exécute <1 sec.
Schéma créé via ce modèle:
DECLARE @TranName VARCHAR(20)
SELECT @TranName = 'MyTransaction'
BEGIN TRANSACTION @TranName
GO
IF NOT EXISTS (SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
WHERE SCHEMA_NAME = '{1}')
BEGIN
EXEC('CREATE SCHEMA [{1}]')
EXEC sp_addextendedproperty @name='User', @value='{0}', @level0type=N'Schema', @level0name=N'{1}'
END
GO
{2}
COMMIT TRANSACTION MyTransaction;
GO
Et {2} est, je crois, une liste de synonymes créés dans ce schéma.
Profil de requête à deux points de la requête:
J'ai ouvert un ticket avec Microsoft.
De plus, nous avons essayé d'ajouter UserB à db_owner
, puis d' ingérer DENY
tous les privilèges que nous connaissons et qui sont associés db_owner
. Le résultat est une requête rapide. Soit nous avons raté quelque chose (tout à fait possible), soit il y a une vérification spéciale pour le db_owner
rôle.