Quando os aplicativos codificam um nome de esquema, dbo.TABLE
, ele reduz a capacidade do DBA de migrar os dados conforme necessário.
É seguro e mais flexível para os aplicativos omitirem nomes de esquema?
Eu sei que você dirá que isso é "baseado em opinião", mas é uma questão crítica para o gerenciamento de bancos de dados.
A resposta curta aqui é Não, não é "seguro" nem "conveniente" e provavelmente não é mais flexível omitir o nome do esquema. Na verdade, fazer isso é uma das formas clássicas de "dar um tiro no pé".
Uma das principais regras de programação é codificar em um estilo defensivo. Essa é uma tática bem conhecida que ajuda a evitar bugs, especialmente os difíceis de rastrear. A programação defensiva é definida como:
É importante notar que cada objeto no SQL Server pertence a um esquema específico. Na maioria das vezes, esse esquema é simplesmente o
dbo
esquema, e pode-se facilmente projetar um banco de dados inteiro cheio de procedimentos armazenados, visualizações, funções, etc. nodbo
esquema. Alguém poderia fazer isso, mas eu não recomendaria, pelas seguintes razões:Isso dificulta a interpretação do código. Observando as duas
SELECT
declarações abaixo, há mais clareza em torno daquela em que o esquema é especificado explicitamente.Como especifiquei
sys.databases
, você sabe instantaneamente e sem dúvida que os resultados virão da visão do sistema. Especificar o esquema torna o código complexo muito mais fácil de entender de forma confiável.A resolução do esquema pode nem sempre funcionar como você pretende. Se você tiver vários esquemas no banco de dados, o SQL Server precisará realizar uma pesquisa de objetos quando você não especificar o esquema. Quando você especifica o esquema, o SQL Server sabe exatamente onde procurar o objeto.
Dois desenvolvedores, Melanie e Hannah, estão trabalhando no código. Melanie tem seu esquema padrão definido como 'Melanie', Hannah tem seu esquema padrão definido como 'Hannah'. Melanie cria a tabela,
x
, inadvertidamente noMelanie
esquema, pois eles não especificaramdbo
naCREATE TABLE
instrução. Melanie diz a Hannah para começar a usar a mesax
. Hannah então passa a usar a tabelax
sem especificar um esquema, mas como ambos os desenvolvedores têm esquemas padrão diferentes atribuídos ao seu login, seu novo código não consegue localizar o objeto. Isso parece um bug para Hannah, enquanto isso, quando Melanie executa o mesmo código , funciona perfeitamente. Se ambos os desenvolvedores especificarem o esquema, eles nunca verão esse bug.Seu banco de dados tem dois esquemas
warehouse
eaccounting
. Ambos os esquemas têm uma tabela chamadaInvoices
. Awarehouse.Invoice
tabela contém detalhes sobre faturas que precisam ser processadas. Aaccounting.Invoices
tabela contém todas as colunas pertinentes à fatura real, como detalhes de cobrança, valor a pagar, etc. O código escrito por um usuário que não tem nemwarehouse
nemaccounting
como esquema padrão, que não especifica o nome do esquema, retornará uma resolução de objeto erro em tempo de execução ou quando o código está sendo salvo no banco de dados. No código abaixo, estou criando as duasinvoices
tabelas, em esquemas separados:Agora, se eu tentar criar uma visão sem especificar esquemas, recebo um erro:
Agora, veja o exemplo de criação de um procedimento armazenado no
dbo
esquema:Quando você executa o código para criar esse procedimento, o SQL Server não relata erros, devido à resolução de nomes adiada do SQL Server. No entanto, quando você vai executar o proc, você recebe o seguinte erro:
O desempenho pode sofrer. De várias maneiras.
Planos de Execução que normalmente seriam compartilhados entre usuários com diferentes esquemas padrão serão armazenados em cache separadamente se a instrução T-SQL referenciada no Plano de Execução não tiver prefixos de esquema. Assim, por exemplo, a seguinte instrução T-SQL simples seria armazenada em cache várias vezes para cada usuário que possui um esquema padrão diferente:
Para um banco de dados complexo, com muitas instruções T-SQL variadas sendo executadas por muitos usuários diferentes, isso pode resultar em um aumento significativo do cache do plano, o que pode afetar negativamente a execução da consulta. Sem mencionar que cada usuário pode obter um plano significativamente diferente dependendo da complexidade das instruções que estão sendo executadas e se a detecção de parâmetros está em jogo.
Em um ambiente onde há muitos esquemas e muitos objetos, especificar o nome do esquema limita o trabalho que o SQL Server deve fazer ao resolver nomes de objetos para IDs de objetos no tempo de compilação. Especificar o esquema pode resultar em uma redução significativa de carga para bancos de dados grandes e ocupados, com código complexo.
A contenção de Spinlock pode se tornar problemática quando você não especifica o esquema. Este documento da Microsoft sobre como diagnosticar e resolver a contenção de Spinlock afirma:
Alguns objetos não possuem um esquema padrão. Veja o exemplo mostrado aqui por Maria Zakourdaev sobre gatilhos DDL. Quando você cria um gatilho do lado do servidor, esse gatilho não tem o conceito de um esquema padrão e, portanto, falhará em tempo de execução , o que pode ser particularmente doloroso. Maria admite no artigo que eles geralmente não especificam esquemas, a menos que o código exija. Eu diria que, se eles tivessem o hábito de sempre especificar o esquema, Maria não teria passado horas perseguindo esse bug.
Em resumo, eu sempre especifico o esquema para cada pedaço de código que escrevo, simplesmente porque não requer quase nenhum esforço ao escrever o código, e isso me garante que certos bugs simplesmente nunca acontecerão.
Especificar o esquema é de baixo custo e alto impacto, o que acho que todos concordamos que é A Good Thing™.
Você parece entender isso, mas apenas no caso... você nem sempre precisa especificar o esquema, desde que o esquema seja o esquema padrão do usuário.
Portanto, você pode lidar com isso no nível de logon do SQL Server. Um login pode ser definido como padrão para, digamos, o esquema 'MySchema'. Para este login, a tabela
mySchema.Orders
seria o padrão para esse usuário, endereçável simplesmenteOrders
.Isso não é usado com frequência, pois pode ficar confuso, mas é uma maneira totalmente funcional de fazer isso. Mas note: se você não tiver a tabela
mySchema.Orders
em seu banco de dados, o sistema irá procurardbo.Orders
também. Isso é ótimo se você quiser algumas tabelas personalizadas e algumas em comum - ruim se osmySchema
usuários não tiverem acesso àsdbo
tabelas.