Cenário: SQL Server 2014 (v12.0.4100.1)
O serviço .NET executa 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 retorna cerca de 6500 linhas, mas geralmente atinge o tempo limite após mais de 3 minutos. O XXXX
acima não é 'dbo'.
Se eu executar esta consulta no SSMS como UsuárioA, a consulta retornará em menos de um segundo.
Quando executada como UsuárioB (que é como o serviço .NET se conecta), a consulta leva de 3 a 6 minutos e tem a% da CPU em 25% (de 4 núcleos) o tempo todo.
UserA é um logon de domínio na função sysadmin.
UserB é um logon SQL com:
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]
Eu posso duplicar isso no SSMS envolvendo o SQL acima em um Execute as...Revert
bloco, para que o código .NET fique fora de cena.
O plano de execução parece o mesmo. Eu diferenciei o XML e existem apenas pequenas diferenças (CompileTime, CompileCPU, CompileMemory).
Todas as estatísticas de E / S não mostram leituras físicas:
Tabela 'sysobjvalues'. Contagem de varredura 0, leituras lógicas 19970, leituras físicas 0, leituras de read-ahead 0, leituras lógicas de lob 0, leituras físicas de lob 0, leituras físicas de lob 0, leituras de read-ahead de lob 0. Tabela 'Arquivo de Trabalho'. Contagem de varreduras 0, leituras lógicas 0, leituras físicas 0, leituras de leitura antecipada 0, leituras lógicas de lob 0, leituras físicas de lob 0, leituras físicas de lob 0, leituras de leitura antecipada de lob 0. Tabela 'Mesa de trabalho'. Contagem de varreduras 0, leituras lógicas 0, leituras físicas 0, leituras de leitura antecipada 0, leituras lógicas de lob 0, leituras físicas de lob 0, leituras físicas de lob 0, leituras de leitura antecipada de lob 0. Tabela 'sysschobjs'. Contagem de varredura 1, leituras lógicas 9122, leituras físicas 0, leituras antecipadas 0, leituras lógicas lob 0, leituras lógicas lob 0, leituras físicas lob 0, leituras antecipadas lob 0. Tabela 'sysclsobjs'. Contagem de varreduras 0, leituras lógicas 2, leituras físicas 0, leituras de leitura antecipada 0, leituras lógicas de lob 0, leituras físicas de lob 0, leituras físicas de lob 0, leituras de leitura antecipada de lob 0.
O status XEvent aguarda (para uma consulta de ~ 3 minutos) é:
+ --------------------- + ------------ + -------------- -------- + ------------------------------ + ---------- ------------------- + | Tipo de espera | Contagem de espera | Tempo total de espera (ms) | Tempo total de espera do recurso (ms) | Tempo total de espera do sinal (ms) | + --------------------- + ------------ + -------------- -------- + ------------------------------- + --------- -------------------- + | SOS_SCHEDULER_YIELD 37300 427 20 407 | NETWORK_IO | 5 26 26 0 | IO_COMPLETION | 3 1 | 1 | 0 + --------------------- + ------------ + -------------- -------- + ------------------------------- + --------- -------------------- +
Se eu reescrever a consulta (no SSMS, não tenho acesso ao código do aplicativo) 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
então, o UsuárioB executa na mesma velocidade (rápida) que o UsuárioA.
Se eu adicionar db_owner
ao UsuárioB, novamente, a consulta será executada <1 s.
Esquema criado através deste modelo:
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
E {2} é, acredito, uma lista de sinônimos criados nesse esquema.
Perfil de consulta em dois pontos da consulta:
Abri um ticket com a Microsoft.
Além disso, tentamos adicionar o UserB e db_owner
, em seguida, DENY
todos os privilégios que sabemos que estão associados db_owner
. O resultado é uma consulta rápida. Perdemos algo (inteiramente possível) ou há uma verificação especial para o db_owner
papel.