Escenario: SQL Server 2014 (v12.0.4100.1)
.NET Service ejecuta esta consulta:
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
... que devuelve alrededor de 6500 filas pero a menudo se agota después de más de 3 minutos. Lo XXXX
anterior no es 'dbo'.
Si ejecuto esta consulta en SSMS como UsuarioA, la consulta vuelve en menos de un segundo.
Cuando se ejecuta como UserB (que es cómo se conecta el servicio .NET), la consulta demora de 3 a 6 minutos y tiene el% de CPU al 25% (de 4 núcleos) todo el tiempo.
UserA es un inicio de sesión de dominio en el rol sysadmin
UserB es un inicio de sesión SQL con:
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]
Puedo duplicar esto en SSMS envolviendo el SQL anterior en un Execute as...Revert
bloque, por lo que el código .NET está fuera de la imagen.
El plan de ejecución se ve igual. Difundí el XML y solo hay pequeñas diferencias (CompileTime, CompileCPU, CompileMemory).
Todas las estadísticas de IO no muestran lecturas físicas:
Tabla 'sysobjvalues'. Cuenta de escaneo 0, lecturas lógicas 19970, lecturas físicas 0, lecturas de lectura anticipada 0, lecturas lógicas lob 0, lecturas físicas lob 0, lecturas de lectura lob 0. Tabla 'Archivo de trabajo'. Recuento de exploración 0, lecturas lógicas 0, lecturas físicas 0, lecturas de lectura anticipada 0, lecturas lógicas lob 0, lecturas físicas lob 0, lecturas de lectura lob 0. Mesa 'Mesa de trabajo'. Recuento de exploración 0, lecturas lógicas 0, lecturas físicas 0, lecturas de lectura anticipada 0, lecturas lógicas lob 0, lecturas físicas lob 0, lecturas de lectura lob 0. Tabla 'sysschobjs'. Cuenta de escaneo 1, lecturas lógicas 9122, lecturas físicas 0, lecturas de lectura anticipada 0, lecturas lógicas lob 0, lecturas físicas lob 0, lecturas de lectura lob 0. Tabla 'sysclsobjs'. Cuenta de escaneo 0, lecturas lógicas 2, lecturas físicas 0, lecturas de lectura anticipada 0, lecturas lógicas lob 0, lecturas físicas lob 0, lecturas lob de lectura anticipada 0.
Los estados de espera de XEvent (para una consulta de ~ 3 minutos) son:
+ --------------------- + ------------ + -------------- -------- + ------------------------------ + ---------- ------------------- + El | Esperar tipo | Espera cuenta | Tiempo de espera total (ms) | Tiempo total de espera de recursos (ms) | Tiempo de espera de señal total (ms) | + --------------------- + ------------ + -------------- -------- + ------------------------------- + --------- -------------------- + El | SOS_SCHEDULER_YIELD | 37300 | 427 20 | 407 El | NETWORK_IO | 5 | 26 | 26 | 0 | El | IO_COMPLETION | 3 | 1 | 1 | 0 | + --------------------- + ------------ + -------------- -------- + ------------------------------- + --------- -------------------- +
Si reescribo la consulta (en SSMS, no tengo acceso al Código de la aplicación) para
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
entonces UserB se ejecuta a la misma velocidad (rápida) que UserA.
Si agrego db_owner
al usuario B, entonces, nuevamente, la consulta se ejecuta <1 seg.
Esquema creado a través de esta plantilla:
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
Y creo que {2} es una lista de sinónimos creados en ese esquema.
Perfil de consulta en dos puntos de la consulta:
Abrí un boleto con Microsoft.
Además, intentamos agregar UserB a db_owner
, y luego incorporar DENY
todos los privilegios con los que sabemos que están asociados db_owner
. El resultado es una consulta rápida. O nos perdimos algo (completamente posible), o hay una verificación especial para el db_owner
papel.