Alguém pode me indicar a documentação correta ou permissões adicionais que eu preciso além do SA para fazer o seguinte?
Ao executá-lo, recebo o seguinte erro:
Não é possível encontrar o objeto "#test" porque ele não existe ou você não tem permissões.
IF NOT EXISTS
(
SELECT
name
FROM sys.server_principals
WHERE
name = 'testlimiteduser'
)
BEGIN
CREATE LOGIN [testlimiteduser] WITH PASSWORD=N'apassword', DEFAULT_DATABASE=[tempdb], CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF
END
IF NOT EXISTS
(
SELECT
name
FROM sys.database_principals
WHERE
name = 'testlimiteduser'
)
BEGIN
CREATE USER [testlimiteduser] FOR LOGIN [testlimiteduser] WITH DEFAULT_SCHEMA=[dbo]
END
IF NOT EXISTS
(
SELECT 1
FROM sys.database_principals AS p
WHERE
p.name like 'testlimiteduser_app'
)
BEGIN
CREATE ROLE testlimiteduser_app
GRANT EXECUTE TO testlimiteduser_app
ALTER ROLE [db_datareader] ADD MEMBER testlimiteduser_app
ALTER ROLE [db_datawriter] ADD MEMBER testlimiteduser_app
ALTER ROLE testlimiteduser_app ADD MEMBER [testlimiteduser]
ALTER ROLE db_owner ADD MEMBER testlimiteduser -- https://learn.microsoft.com/en-us/sql/t-sql/database-console-commands/dbcc-updateusage-transact-sql?view=sql-server-2017 says db_owner or SA
END
GO
exec as user='testlimiteduser'
drop table if exists #test
create table #test (id int )
exec('UPDATE STATISTICS #test WITH ROWCOUNT = 1000000')
select * from #test
revert;
Verificando a documentação em https://learn.microsoft.com/en-us/sql/t-sql/database-console-commands/dbcc-updateusage-transact-sql?view=sql-server-2017 diz que db_owner ou SA são tudo bem, mas nem parece que db_owner funciona nos meus testes.
Fazer uma conta
db_owner
, mesmo para[tempdb]
ele, ainda é arriscado. Felizmente, não é necessário fazer isso para atingir a meta. Você pode simplesmente usar a assinatura de módulo para permitir que um procedimento armazenado que reside no[tempdb]
uso dadb_owner
função de banco de dados:Configuração inicial
Isso apenas nos leva ao mesmo estado que o código fornecido na pergunta (menos o
testlimiteduser_app
papel, que é desnecessário para esse objetivo).Configuração básica
Precisamos de um módulo que possa ser assinado (o SQL ad hoc não funcionará), mas ainda não o estamos assinando.
Aqui nós:
TESTE 1
Observe: é melhor usar
EXECUTE AS LOGIN
, não apenasAS USER
porqueLOGIN
é mais preciso em termos do que acontece quando o aplicativo realmente se conecta ao SQL Server, masUSER
também adiciona restrições que podem distorcer o comportamento/resultados do teste.Configuração de assinatura do módulo
[master]
TESTE 2
Assinamos o procedimento armazenado e o associamos a um login, mas ainda não demos a permissão necessária a esse login, portanto, os resultados são os mesmos.
Configuração final: atribuir permissão para login OU usuário
Isso foi mantido como uma etapa separada apenas para deixar bem claro que é realmente a assinatura do módulo que está fazendo isso funcionar. E você tem duas opções (escolha apenas uma):
adicione o login baseado em certificado existente à
sysadmin
função no nível da instânciaOU:
Crie um usuário a
tempdb
partir do login baseado em certificado e adicione o novo usuário àdb_owner
função no nível do banco de dadosTESTE 3
Conclusão
As principais diferenças entre as opções são:
tempdb
(que precisa ser criado a cada início do serviço SQL Server)sysadmin
a permissão é mais poderosa (não exatamente "menos privilegiada")db_owner
é mais contido quesysadmin
, em termos de potênciatempdb
(que precisa ser criado a cada inicialização do serviço SQL Server)A diferença entre
sysadmin
e db_owner` é mínima, se não relevante aqui, pois a única coisa que pode ser feita com qualquer uma dessas permissões é o que o código no procedimento armazenado faz (este é um dos principais benefícios da assinatura de módulo: é altamente granular).Portanto, em um nível prático, a complexidade de criar o usuário
tempdb
e adicioná-lo adb_owner
cada inicialização do serviço SQL Server (que requer a criação de um procedimento armazenado emmaster
, marcando-o como um "procedimento de inicialização" e habilitando a configuração em nível de instância opção "scan for startup procs") é pior do que fazer o loginsysadmin
.Se o banco de dados que precisa da permissão adicional fosse um banco de dados de usuário, eu provavelmente usaria a Opção 2, mesmo que apenas com o objetivo de tê-lo mais próximo do uso pretendido, em vez de ser uma preocupação real com relação
sysadmin
aodb_owner
.Para obter uma explicação detalhada das etapas seguidas para aplicar a assinatura do módulo, consulte minha postagem:
Use com segurança e facilidade permissões de alto nível sem concedê-las a ninguém: no nível do servidor
Para obter mais informações sobre a assinatura do módulo em geral, consulte minha postagem:
POR FAVOR, por favor, por favor, pare de usar personificação, TRUSTWORTHY e encadeamento de propriedade entre bancos de dados
Você precisa executar
exec('UPDATE STATISTICS #test WITH ROWCOUNT = 1000000')
dentro do banco de dados tempdb.Basicamente, as tabelas temporárias existem no tempdb, não em outros.
Eh, parece que eu estava em erro. A resposta é simples: o usuário não tem permissões no banco de dados tempdb para executar este comando de atualização de estatísticas
As tabelas temporárias são criadas no banco de dados tempdb e as permissões por padrão são limitadas.
Existem quatro tipos de tabelas:
GO
separador de lote ou no final do scriptVale a pena notar que os objetos Temp podem ser referenciados via
tempdb..#tablename
, embora o uso explícito do nome tempdb em instruções normais seja ignorado, pois todas as tabelas temporárias são criadas noTempdb
e nodbo
esquemaObserve como todos eles estão no banco de dados tempdb. A razão pela qual sua instrução está falhando é simplesmente devido à tabela #temp existente no tempdb e você provavelmente não deu ao usuário permissões no tempdb para realizar a atualização.
Normalmente, tudo o que você precisa para conceder alter na tabela, embora eu tenha descoberto que as tabelas temporárias são um pouco diferentes e podem exigir permissões mais altas. mas como esta é a mesma sessão, basta fazer isso:
Agora você nem precisa conceder permissões elevadas ao usuário e satisfez seu problema.
Eu fiz algumas pesquisas adicionais e encontrei o seguinte: Qualquer consulta na tabela temporária funciona bem, é o WITH ROWCOUNT que causa o problema. Um padrão UPDATE STATISTICS também prossegue sem problemas.
Passei pela documentação do MSDN e não encontrei uma nota explícita para as permissões SET ROWCOUNT combinadas com UPDATE STATISTICS - após algumas especulações e testes, descobri que a documentação do DBCC UPDATEUSAGE estabelece a necessidade de sysadmin ou db_owner no banco de dados que contém o tabela.
Se você adicionar isso ao meu exemplo, o código funciona:
Infelizmente, meu código original não esclareceu que está sendo executado em outro banco de dados além do tempdb, mas essa é a suposição implícita de que, se você ignorar, todo o script funcionará (porque agora eles têm tempdb db_owner.)