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.
access check cache bucket count
etaccess check cache quota
auparavant. Faudra jouer un peu avec ceux-ci.WHILE(1=1) BEGIN DBCC FREESYSTEMCACHE ('TokenAndPermUserStore') WAITFOR DELAY '00:00:05' END
en boucle pour toujours, la requête se termine en moins de 2 minutes contre 8 minutes en général.Si cela est toujours en ligne - nous avons eu le même problème - il semble que si vous êtes le dbo ou un administrateur système, alors tout accès à sys.objects (ou quelque chose comme ça) - alors c'est instantané sans vérification contre les objets individuels.
si c'est un db_datareader modeste, il doit vérifier chaque objet à son tour ... il est caché dans le plan de requête car ceux-ci se comportent plus comme des fonctions que des vues / tables
le plan est le même, mais il fait des choses différentes derrière le capot
la source
L'utilisation de l'indicateur de trace 9481 semble résoudre ce problème pour moi.
Le CE (Cardinality Estimator) en 2014 (compat 120) a changé de 2012 à 2008, et en utilisant TF 9481 force l'utilisation du 2012 CE.
Voir L'estimateur de cardinalité SQL 2014 mange du mauvais TSQL pour le petit-déjeuner de Kendra Little.
la source