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.
access check cache bucket count
eaccess check cache quota
anteriormente. Vai ter que brincar um pouco com eles.WHILE(1=1) BEGIN DBCC FREESYSTEMCACHE ('TokenAndPermUserStore') WAITFOR DELAY '00:00:05' END
em um loop para sempre, a consulta é concluída em menos de 2 minutos versus 8 minutos normalmente.Se isso ainda estiver ativo - tivemos o mesmo problema -, parece que, se você é o dbo ou um administrador de sistema, qualquer acesso ao sys.objects (ou algo assim) - é instantâneo, sem verificação de objetos individuais.
se é um db_datareader humilde, ele deve verificar cada objeto por vez ... está oculto no plano de consulta, pois eles se comportam mais como funções do que visualizações / tabelas
o plano parece o mesmo, mas está fazendo coisas diferentes por trás do capô
fonte
Usar o sinalizador de rastreamento 9481 parece resolver esse problema para mim.
O CE (Cardinality Estimator) em 2014 (compat 120) mudou de 2012 e 2008, e o uso do TF 9481 força o uso do CE de 2012.
Consulte O estimador de cardinalidade do SQL 2014 come TSQL incorreto no café da manhã por Kendra Little.
fonte