Partilhar via


Agrupamentos de banco de dados contidos

Aplica-se a:SQL ServerAzure SQL Managed Instance

Várias propriedades afetam a ordem de classificação e a semântica de igualdade de dados textuais, incluindo diferenciação de maiúsculas e minúsculas, sensibilidade de acento e a linguagem base que está sendo usada. Essas qualidades são expressas ao SQL Server por meio da escolha do agrupamento para os dados. Para obter uma discussão mais aprofundada sobre os próprios agrupamentos, consulte Suporte a agrupamento e Unicode.

Os agrupamentos se aplicam não apenas aos dados armazenados em tabelas de usuário, mas a todo o texto manipulado pelo SQL Server, incluindo metadados, objetos temporários, nomes de variáveis, etc. O tratamento destes difere em bases de dados contidas e não contidas. Essa alteração não afeta muitos usuários, mas ajuda a fornecer independência e uniformidade de instância. Mas isso também pode causar alguma confusão e problemas para sessões que acessam bancos de dados contidos e não contidos.

O comportamento de agrupamento de bancos de dados contidos difere sutilmente do comportamento em bancos de dados não contidos. Esse comportamento geralmente é benéfico, proporcionando independência e simplicidade na gestão de instâncias. Alguns usuários podem ter problemas, especialmente quando uma sessão acessa bancos de dados contidos e não contidos.

Este artigo esclarece o conteúdo da alteração e examina as áreas em que a alteração pode causar problemas.

Observação

Para o Banco de Dados SQL do Azure, os agrupamentos para bancos de dados contidos são diferentes. O agrupamento de banco de dados e o agrupamento de catálogos podem ser definidos na criação do banco de dados e não podem ser atualizados. Especifique um agrupamento para dados (COLLATE) e um agrupamento de catálogo para metadados do sistema e identificadores de objeto (CATALOG_COLLATION). Para obter mais informações, consulte CREATE DATABASE.

Bases de dados não incluídas

Todos os bancos de dados têm um agrupamento padrão (que pode ser definido ao criar ou alterar um banco de dados). Esse agrupamento é usado para todos os metadados no banco de dados e o padrão para todas as colunas de cadeia de caracteres dentro do banco de dados. Os usuários podem escolher um agrupamento diferente para qualquer coluna específica usando a COLLATE cláusula.

Exemplo 1

Por exemplo, se estivéssemos a trabalhar em Pequim, poderíamos usar uma ordenação chinesa.

ALTER DATABASE MyDB
    COLLATE Chinese_Simplified_Pinyin_100_CI_AS;

Agora, se criarmos uma coluna, seu agrupamento padrão é esse agrupamento chinês, mas podemos escolher outro se quisermos:

CREATE TABLE MyTable
(
    mycolumn1 NVARCHAR,
    mycolumn2 NVARCHAR COLLATE Frisian_100_CS_AS
);
GO

SELECT name, collation_name
FROM sys.columns
WHERE name LIKE 'mycolumn%';
GO

Aqui está o conjunto de resultados.

name            collation_name
--------------- ----------------------------------
mycolumn1       Chinese_Simplified_Pinyin_100_CI_AS
mycolumn2       Frisian_100_CS_AS

Isto parece relativamente simples, mas surgem vários problemas. Como o agrupamento de uma coluna depende do banco de dados no qual a tabela é criada, surgem problemas com o uso de tabelas temporárias armazenadas no tempdb. O agrupamento de tempdb normalmente corresponde ao agrupamento da instância, que não precisa corresponder ao agrupamento do banco de dados.

Exemplo 2

Por exemplo, considere o banco de dados (chinês) mostrado anteriormente, quando usado em uma instância com um Latin1_General agrupamento:

CREATE TABLE T1 (T1_txt NVARCHAR (MAX));
GO

CREATE TABLE #T2 (T2_txt NVARCHAR (MAX));
GO

À primeira vista, essas duas tabelas parecem ter o mesmo esquema, mas como os agrupamentos dos bancos de dados diferem, os valores são incompatíveis:

SELECT T1_txt, T2_txt
FROM T1
     INNER JOIN #T2
         ON T1.T1_txt = #T2.T2_txt;

Aqui está o conjunto de resultados.

Msg 468, Nível 16, Estado 9, Linha 2

Não é possível resolver o conflito de agrupamento entre "Latin1_General_100_CI_AS_KS_WS_SC" e "Chinese_Simplified_Pinyin_100_CI_AS" na operação igual a.

Podemos corrigir isso ordenando explicitamente a tabela temporária. O SQL Server facilita isso fornecendo a DATABASE_DEFAULT palavra-chave para a COLLATE cláusula.

CREATE TABLE T1 (T1_txt NVARCHAR (MAX));
GO

CREATE TABLE #T2 (T2_txt NVARCHAR (MAX) COLLATE DATABASE_DEFAULT);
GO

SELECT T1_txt, T2_txt
FROM T1
     INNER JOIN #T2
         ON T1.T1_txt = #T2.T2_txt;

Esta consulta agora é executada sem erros.

Também podemos ver o comportamento dependente da ordenação com variáveis. Considere a seguinte função:

CREATE FUNCTION f (@x INT)
RETURNS INT
AS
BEGIN
    DECLARE @I AS INT = 1;
    DECLARE @İ AS INT = 2;
    RETURN @x * @i;
END

Esta é uma função bastante peculiar. Num agrupamento que diferencia maiúsculas de minúsculas, a cláusula @i na cláusula de retorno não pode se vincular a nenhum @I ou . Em um agrupamento de Latin1_General que não diferencia maiúsculas de minúsculas, @i liga-se a @I, e a função retorna 1. Mas em um agrupamento turco que não diferencia maiúsculas de minúsculas, @i liga-se a , e a função retorna 2. Isso pode causar estragos em um banco de dados que se move entre instâncias com agrupamentos diferentes.

Bases de dados incluídas

Como um objetivo de design dos bancos de dados contidos é torná-los autossuficientes, a dependência da instância e tempdb dos agrupamentos deve ser cortada. Para fazer isso, os bancos de dados contidos introduzem o conceito de agrupamento de catálogo. O agrupamento de catálogo é usado para metadados do sistema e objetos transitórios. Os detalhes são fornecidos da seguinte forma.

Em um banco de dados contido, o agrupamento de catálogo é Latin1_General_100_CI_AS_WS_KS_SC. Esse agrupamento é o mesmo para todos os bancos de dados contidos em todas as instâncias do SQL Server e não pode ser alterado.

O agrupamento do banco de dados é mantido, mas é usado apenas como o agrupamento padrão para dados do usuário. Por padrão, a ordenação do banco de dados é igual à ordenação do banco de dados model, mas pode ser alterada pelo usuário por meio de um comando CREATE ou ALTER DATABASE, como acontece com bancos de dados não contidos.

Uma nova palavra-chave, CATALOG_DEFAULT, está disponível na COLLATE cláusula. Isso é usado como um atalho para o agrupamento atual de metadados em bancos de dados contidos e não contidos. Ou seja, em um banco de dados não contido, CATALOG_DEFAULT retorna o agrupamento de banco de dados atual, uma vez que os metadados são agrupados no agrupamento de banco de dados. Em um banco de dados contido, esses dois valores podem ser diferentes, já que o usuário pode alterar o agrupamento do banco de dados para que ele não corresponda ao agrupamento do catálogo.

O comportamento de vários objetos em bancos de dados não contidos e contidos é resumido nesta tabela:

Item Base de dados não isolada Base de dados contida
Dados do usuário (padrão) DATABASE_DEFAULT DATABASE_DEFAULT
Dados temporários (padrão) tempdb ordenação DATABASE_DEFAULT
Metadados DATABASE_DEFAULT / CATALOG_DEFAULT CATALOG_DEFAULT
Metadados temporários tempdb ordenação CATALOG_DEFAULT
Variáveis Agrupamento de instâncias CATALOG_DEFAULT
Etiquetas de goto Colação de instâncias CATALOG_DEFAULT
Nomes dos cursores Agrupamento de instâncias CATALOG_DEFAULT

No exemplo de tabela temporária descrito anteriormente, podemos ver que esse comportamento de agrupamento elimina a necessidade de uma cláusula explícita COLLATE na maioria dos usos de tabela temporária. Em um banco de dados contido, esse código agora é executado sem erros, mesmo que os agrupamentos de banco de dados e instância sejam diferentes:

CREATE TABLE T1 (T1_txt NVARCHAR (MAX));
GO

CREATE TABLE #T2 (T2_txt NVARCHAR (MAX));
GO

SELECT T1_txt, T2_txt
FROM T1
     INNER JOIN #T2
         ON T1.T1_txt = #T2.T2_txt;

Esta consulta funciona porque tanto T1_txt quanto T2_txt são diferenciados pelo agrupamento de colação do banco de dados contido.

Cruzamento entre contextos contidos e não contidos

Enquanto uma sessão em um banco de dados contido permanecer contida, ela deve permanecer dentro do banco de dados ao qual se conectou. Neste caso, o comportamento é simples. Mas se uma sessão cruza entre contextos contidos e não contidos, o comportamento torna-se mais complexo, uma vez que os dois conjuntos de regras devem ser interligados. Isso pode acontecer em um banco de dados parcialmente contido, uma vez que um usuário pode USE ir para outro banco de dados. Neste caso, a diferença nas regras de agrupamento é tratada pelo seguinte princípio.

  • O comportamento de agrupamento para um lote é determinado pelo banco de dados no qual o lote começa.

Esta decisão é tomada antes de quaisquer comandos serem emitidos, incluindo a inicial USE. Ou seja, se um lote começar em um banco de dados contido, mas o primeiro comando for USE para um banco de dados não contido, o comportamento de agrupamento contido ainda será usado para o lote. Dado esse cenário, uma referência a uma variável, por exemplo, pode ter vários resultados possíveis:

  • A referência pode encontrar exatamente uma correspondência. Neste caso, a referência funciona sem erros.

  • A referência pode não encontrar uma correspondência na ordenação atual onde anteriormente havia uma. Isso gera um erro indicando que a variável não existe, mesmo que aparentemente tenha sido criada.

  • A referência pode acabar encontrando múltiplas correspondências que eram originalmente distintas. Isso também gera um erro.

Ilustramos isto com alguns exemplos. Para estes, assumimos que há um banco de dados parcialmente contido nomeado MyCDB com seu agrupamento de banco de dados definido como o agrupamento padrão, Latin1_General_100_CI_AS_WS_KS_SC. Assumimos que o agrupamento de instâncias é Latin1_General_100_CS_AS_WS_KS_SC. Os dois agrupamentos diferem apenas na sensibilidade às maiúsculas e minúsculas.

Exemplo 1

O exemplo a seguir ilustra o caso em que a referência encontra exatamente uma correspondência.

USE MyCDB;
GO

CREATE TABLE #a (x INT);

INSERT INTO #a VALUES (1);
GO

USE master;
GO

SELECT * FROM #a;
GO

Results:

Aqui está o conjunto de resultados.

x
-----------
1

Nesse caso, o #a identificado se associa tanto no agrupamento de catálogo que não distingue maiúsculas de minúsculas quanto no agrupamento de instâncias que distingue maiúsculas de minúsculas, e o código funciona.

Exemplo 2

O exemplo a seguir ilustra o caso em que a referência não encontra uma correspondência na ordenação atual, enquanto anteriormente existia uma.

USE MyCDB;
GO

CREATE TABLE #a (x INT);

INSERT INTO #A VALUES (1);
GO

Aqui, #A liga-se a #a no agrupamento predefinido insensível a maiúsculas e minúsculas, e a inserção funciona,

Aqui está o conjunto de resultados.

(1 row(s) affected)

Mas se continuarmos o guião...

USE master;
GO

SELECT * FROM #A;
GO

Recebemos um erro ao tentar vincular a #A no intercalamento de instâncias com sensibilidade a maiúsculas e minúsculas;

Aqui está o conjunto de resultados.

Msg 208, Level 16, State 0, Line 2
Invalid object name '#A'.

Exemplo 3

O exemplo a seguir ilustra o caso em que a referência encontra várias correspondências que eram originalmente distintas. Primeiro, começamos em tempdb (que tem o mesmo agrupamento sensível a maiúsculas e minúsculas que nossa instância) e executamos as instruções a seguir.

USE tempdb;
GO

CREATE TABLE #a (x INT);
GO

CREATE TABLE #A (x INT);
GO

INSERT INTO #a VALUES (1);
GO

INSERT INTO #A VALUES (2);
GO

Esta consulta é bem-sucedida, uma vez que as tabelas são distintas neste agrupamento:

Aqui está o conjunto de resultados.

(1 row(s) affected)
(1 row(s) affected)

No entanto, se passarmos para a nossa base de dados contida, verificamos que já não podemos ligar-nos a estas tabelas.

USE MyCDB;
GO

SELECT * FROM #a;
GO

Aqui está o conjunto de resultados.

Msg 12800, Level 16, State 1, Line 2
The reference to temp table name #a is ambiguous and cannot be resolved. Possible candidates are #a and #A.