Compartilhar via


Ordenações de banco de dados independentes

Aplica-se a:SQL ServerInstância Gerenciada de SQL do Azure

Várias propriedades afetam a ordem de classificação e a semântica de igualdade dos dados textuais, incluindo diferenciação de maiúsculas e minúsculas, distinção de acentos e o idioma base em uso. Essas qualidades são demonstradas para o SQL Server pela escolha da ordenação dos dados. Para obter uma discussão mais detalhada sobre ordenações em si, consulte Ordenação e suporte a Unicode.

As ordenações se aplicam não apenas aos dados armazenados nas tabelas de usuário, mas também a todo o texto tratado pelo SQL Server, incluindo metadados, objetos temporários, nomes de variável etc. O tratamento deles varia nos bancos de dados dependentes e independentes. Essa alteração não afeta muitos usuários, mas ajuda a fornecer independência e uniformidade da instância. Mas isso também pode causar alguma confusão e problemas para sessões que acessam bancos de dados independentes e não contidos.

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

Este artigo esclarece o conteúdo da alteração e examina á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 independentes são diferentes. A ordenação de banco de dados e a ordenação de catálogo podem ser definidas na criação do banco de dados e não podem ser atualizadas. Especifique uma ordenação para os dados (COLLATE) e uma ordenação de catálogo para os metadados do sistema e identificadores de objeto (CATALOG_COLLATION). Para saber mais, confira CRIAR BANCO DE DADOS.

Bancos de dados dependente

Todos os bancos de dados têm uma ordenação padrão (que pode ser definida ao criar ou alterar um banco de dados). Essa ordenação é usada 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 uma ordenação diferente para qualquer coluna específica usando a cláusula COLLATE.

Exemplo 1

Por exemplo, se estivéssemos trabalhando em Beijing, nós poderíamos usar uma ordenação de chinês:

ALTER DATABASE MyDB
    COLLATE Chinese_Simplified_Pinyin_100_CI_AS;

Agora, se criarmos uma coluna, sua ordenação padrão é essa ordenação chinesa, mas podemos escolher outra 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

Veja a seguir o conjunto de resultados.

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

Isso parece relativamente simples, mas vários problemas ocorrem. Como a ordenação de uma coluna depende do banco de dados no qual a tabela é criada, surgem problemas com o uso de tabelas temporárias armazenadas em tempdb. Geralmente, a ordenação de tempdb corresponde à ordenação da instância, que não precisa corresponder à ordenação do banco de dados.

Exemplo 2

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

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 as ordenações 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;

Veja a seguir o conjunto de resultados.

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

Não é possível resolver o conflito de ordenação entre "Latin1_General_100_CI_AS_KS_WS_SC" e "Chinese_Simplified_Pinyin_100_CI_AS" na operação de igualdade.

Podemos corrigir isso agrupando 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;

Essa consulta agora é executada sem erros.

Também é possível observar o comportamento dependente de 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

Essa é uma função bastante peculiar. Em uma ordenação que diferencia maiúsculas de minúsculas, a cláusula de retorno @i não pode ser associada a @I ou a . Em uma ordenação Latin1_General sem distinção entre maiúsculas e minúsculas, @i é vinculada a @I, e a função retorna 1. Porém, em uma ordenação em turco sem distinção entre maiúsculas e minúsculas, @i é vinculada a , e a função retorna 2. Isso pode causar confusão em um banco de dados que se move entre instâncias com ordenações diferentes.

Bancos de dados contidos

Como um objetivo de design dos bancos de dados independentes é torná-los dependentes, a dependência da instância e das ordenações tempdb deve ser removida. Para isso, os bancos de dados independentes apresentam o conceito de ordenação de catálogo. A ordenação de catálogo é usada para metadados de sistema e objetos transitórios. Os detalhes são fornecidos da seguinte maneira.

Em um banco de dados contido, a ordenação do catálogo é Latin1_General_100_CI_AS_WS_KS_SC. Essa ordenação é a mesma para todos os bancos de dados contidos em todas as instâncias do SQL Server e não pode ser alterada.

A ordenação de banco de dados é mantida, mas é usada somente como a ordenação padrão para dados de 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 nos bancos de dados dependentes.

Uma nova palavra-chave, CATALOG_DEFAULT, está disponível na cláusula COLLATE. Ela é usada como um atalho para a ordenação 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 a ordenação de banco de dados atual, uma vez que os metadados são agrupados na ordenação do banco de dados. Em um banco de dados independente, esses dois valores podem ser diferentes, pois o usuário pode alterar a ordenação do banco de dados para que ele não corresponda à ordenação do catálogo.

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

Item Banco de dados não contido Banco de dados contido
Dados do usuário (padrão) DATABASE_DEFAULT DATABASE_DEFAULT
Dados temporários (padrão) tempdb Agrupamento DATABASE_DEFAULT
Metadados DATABASE_DEFAULT / CATALOG_DEFAULT CATALOG_DEFAULT
Metadados temporários tempdb Ordenação CATALOG_DEFAULT
Variáveis Ordenação de instância CATALOG_DEFAULT
Marcadores goto Relacionamento de instância CATALOG_DEFAULT
Nomes de cursor Colação de instância CATALOG_DEFAULT

No exemplo da tabela temp descrito anteriormente, podemos ver que esse comportamento de ordenação elimina a necessidade de uma cláusula COLLATE explícita na maioria dos usos da tabela temp. Em um banco de dados contido, esse código agora é executado sem erro, mesmo que as ordenações de banco de dados e de 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;

Essa consulta funciona porque ambos T1_txt e T2_txt são intercalados no ordenamento do banco de dados do banco de dados contido.

Cruzamento entre contextos contidos e descontidos

Desde que uma sessão em um banco de dados contido permaneça contida, ela deve permanecer no banco de dados ao qual está conectada. Nesse caso, o comportamento é simples. Mas se uma sessão cruzar entre contextos contidos e não contidos, o comportamento se tornará mais complexo, pois os dois conjuntos de regras deverão ser ligados. Isso pode acontecer em um banco de dados parcialmente contido, já que um usuário pode USE acessar outro banco de dados. Nesse caso, a diferença nas regras de ordenação é tratada pelo princípio a seguir.

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

Essa decisão é tomada antes que todos os comandos sejam emitidos, incluindo um inicial USE. Ou seja, se um lote começar em um banco de dados independente, mas o primeiro comando for USE para um banco de dados não contido, o comportamento de ordenação independente ainda será usado para o lote. Considerando 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. Nesse caso, a referência funciona sem erros.

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

  • A referência pode encontrar várias correspondências que eram originalmente distintas. Isso também gera um erro.

Ilustramos isso com alguns exemplos. Para eles, presumimos que haja um banco de dados parcialmente contido nomeado MyCDB com sua ordenação de banco de dados definida como a ordenação Latin1_General_100_CI_AS_WS_KS_SCpadrão. Presumimos que a collation da instância seja Latin1_General_100_CS_AS_WS_KS_SC. As duas ordenações são distintas apenas na diferenciação de maiúsculas e minúsculas.

Exemplo 1

O exemplo a seguir mostra o caso onde a referência localiza uma correspondência exata.

USE MyCDB;
GO

CREATE TABLE #a (x INT);

INSERT INTO #a VALUES (1);
GO

USE master;
GO

SELECT * FROM #a;
GO

Results:

Veja a seguir o conjunto de resultados.

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

Nesse caso, o símbolo #a identificado é associado à ordenação de catálogo sem diferenciação de maiúsculas/minúsculas e a ordenação de instância com diferenciação de maiúsculas/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 em que havia uma antes.

USE MyCDB;
GO

CREATE TABLE #a (x INT);

INSERT INTO #A VALUES (1);
GO

Aqui, #A se vincula a #a na ordenação padrão sem distinção entre maiúsculas e minúsculas, e a inserção funciona,

Veja a seguir o conjunto de resultados.

(1 row(s) affected)

Mas se continuarmos o script...

USE master;
GO

SELECT * FROM #A;
GO

Ocorre um erro ao tentar vincular-se a #A na ordenação de instâncias com distinção entre maiúsculas e minúsculas;

Veja a seguir o conjunto de resultados.

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

Exemplo 3

O exemplo a seguir demonstra o caso em que a referência localiza várias correspondências que eram originalmente distintas. Primeiro, iniciamos em tempdb (que tem a mesma ordenação sensível a maiúsculas e minúsculas da nossa instância) e executamos as seguintes instruções.

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

Essa consulta é bem-sucedida, pois as tabelas são distintas nesta ordenação:

Veja a seguir o conjunto de resultados.

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

Se entrarmos em nosso banco de dados contido, no entanto, descobriremos que não podemos mais associar a essas tabelas.

USE MyCDB;
GO

SELECT * FROM #a;
GO

Veja a seguir 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.