Ir al contenido principal

¿Qué es la Intercalación (Collation) en SQL Server? ¿Es posible cambiar la Intercalación de una base de datos?

Este capítulo explica el concepto de Intercalación (Collation) de las bases de datos SQL Server. Se explica las consideraciones de configuración de Intercalación (Collation) a nivel de instancia de SQL Server (es decir, de las bases de datos del sistema), peculiaridades de la configuración de Instancia a nivel de de base de datos (distintas bases de datos pueden utilizar una Intercalación diferente), etc. También se explica cómo cambiar la intercalación de una columna (ALTER TABLE ALTER COLUMN COLLATE), cómo cambiar la intercalación de una base de datos, la utilización de la función fn_helpcollations, la utilización de la palabra clave COLLATE en la cláusula WHERE, etc.

El concepto de Intercalación (Collation) hace referencia al patrón de bits utilizado para representar/almacenar cada carácter, y en consecuencia también se refiere a las reglas utilizadas para ordenar y comparar caracteres. Evidentemente, se trata de un concepto que afecta sólo a los campos de texto.
En la instalación de SQL Server se indica la Intercalación (Collation) de la Instancia, que definirá la intercalación utilizada por las bases de datos del sistema. De aquí podemos inferir (de hecho, es así), que todas las bases de datos del sistema utilizan la misma Intercalación (Collation). Como anécdota, en una ocasión me encontré con una Instancia que durante un proceso de recuperación de una catástrofe, dejaron las bases de datos master y msdb con una intercalación, y las bases de datos model y tempdb con una intercalación diferente (reinstalarón SQL Server con una Intercalación distinta a la original, y posteriormente, recuperaron master y msdb). La Instancia funcionaba aparentemente bien, pero empezamos a encontrar que algunas tareas realizadas con el Enterprise Manager (era una instalación de SQL Server 2000 Enterprise), producía un error, como era el caso de agregar un usuario a una base de datos. Investigando (con trazas, y un poquitín de tiempo), encontramos que Enterprise Manager utilizaba para dicha acción un procedimiento almacenado que creaba una tabla temporal (sobre tempdb, evidentemente) con datos obtenidos de master, y seguidamente hacía un join a través de campos de texto entre dicha tabla temporal y otras tablas de master. El error evidente: La intercalación era distinta, y dicho procedimiento almacenado no se podía ejecutar. De aquí podemos sacar como moraleja, la importancia de tener bien identificada y documentada la Intercalación utilizada por nuestras Instancias y bases de datos de SQL Server, tanto para recuperación de catástrofes como en otros procesos como migraciones y consolidaciones de servidores, etc.
Otra particularidad de la Intercalación (Collation) de una Instancia de SQL Server, es que siempre que se cree una base de datos, por defecto se creará utilizando la Intercalación de la Instancia, excepto que especifiquemos lo contrario.
Aunque la Intercalación (Collation) de todas las bases de datos del sistema debe ser la misma, la Intercalación (Collation) de cada base de datos de usuario puede ser diferente, es decir, podemos tener una base de datos utilizando una Intercalación por requisitos de la aplicación que la utiliza, y otra base de datos de la misma Instancia de SQL Server, utilizando una Intercalación diferente, siendo ésta una configuración natural y habitual.
Es importante tener en cuenta que la Intercalación (Collation) de una base de datos, sólo afecta a:
  • La Intercalación de las tablas y objetos del sistema.
  • La Intercalación de las nuevas tablas y objetos que se creen en la base de datos. Esto es debido, a que si no se especifica de forma explícita la Intercalación deseada en la sentencia CREATE correspondiente, se tomará por defecto la Intercalación de la base de datos.
Es posible cambiar la Intercalación de una base de datos utilizando el comando ALTER DATABASE COLLATE (ej: ALTER DATABASE miBaseDatos COLLATE Modern_Spanish_CI_AS). Sin embargo, lo más probable es que no consigamos lo que creemos estar consiguiendo (ya me decían de pequeño: "hay que tener cuidado con lo que se pide"... jeje ;-). El comando ALTER DATABASE COLLATE se limita a cambiar la Intercalación (Collation) de las tablas del sistema de la base de datos y el valor de Intercalación que por defecto utilizarán los nuevos objetos que se creen sin especificar de forma explícita la Intercalación deseada. Sin embargo, ALTER DATABASE COLLATE no cambiará la intercalación de las tablas existentes. Si deseamos cambiar la Intercalación de una base de datos y de todos sus objetos, una solución es crear una nueva base de datos con la Intercalación deseada, generar el Script de creación de objetos de la base de datos original (sin especificar la Intercalación en dicho Script), ejecutar el Script en la nueva base de datos, y cargar los datos desde la base de datos original utilizando el Asistente de Importación de SQL Server (Import Data). Esta no es la única opción posible, pero en general, es quizás la más apropiada (en general... en cada caso específico, habría que ver). También podemos crear a mano las descargas y cargas de las tablas, con la utilidad BCP.EXE y/o con el comando BULK INSERT, pero a fin de cuentas, esto es lo que hará el Asistente de Importación de forma automática para todas las tablas, así que para qué perder el tiempo, ¿no?. También cabe la posibilidad de utilizar el comando ALTER TABLE ALTER COLUMN COLLATE (ej: ALTER TABLE Facturas ALTER COLUMN ClientID CHAR(10) COLLATE Modern_Spanish_CI_AS), sin embargo, en el momento en que el campo que deseamos alterar tenga definido sobre él un índice, una clave externa, etc., la ejecución de dicho ALTER TABLE será fallida, produciéndose un error como el siguiente:
Server: Msg 5074, Level 16, State 8, Line 1
The object 'PK_Facturas' is dependent on column 'cod'.
Server: Msg 4922, Level 16, State 1, Line 1
ALTER TABLE ALTER COLUMN cod failed because one or more objects access this column.
Evidentemente, eliminar los índices, claves externas, etc., y luego volver a crearlos, es un trabajo extra que tendremos que considerar si realmente nos interesa asumir.
También es posible definir un valor de Intercalación distinto para cada campo de cada tabla. De éste modo, podríamos tener en cada campo de texto de cada tabla, una Intercalación distinta, lo cual se trata de una posibilidad que ofrece gran flexibilidad. Sin embargo, puede producirse un efecto colateral: en algunas instalaciones que he conocido, me he encontrado que en una misma base de datos conviven tablas con diferentes intercalaciones, no porque se desee, sino por descuido de los programadores. Al principio no hay problema, hasta que llega ese momento en el cual deseamos hacer alguna consulta y no podemos (ej: un JOIN entre dos campos de texto con distintas intercalaciones sin utilizar COLLATE en dicho JOIN).
Para conocer las distintas Intercalaciones que tenemos disponibles, podemos consultar la función del sistema fn_helpcollations (ej: select * from ::fn_helpcollations()).
En la práctica, habitualmente al crear una base de datos se crea con la Intercalación por defecto de la Instancia (que ya vimos que se determinó en la instalación de la Instancia), de tal modo que al crear las tablas en la base de datos, sus campos de texto se crean con la Intercalación por defecto de la base de datos. Esto, siempre y cuando no se especifique de forma explícita la Intercalación en las sentencias DDL.
Otro problema habitual relacionado con la Intercalación (Collation), es cuando deseamos realizar consultas entre tablas realizando un JOIN entre campos de texto con distinta Intercalación. Esto no es posible de realizar (obtendremos un error como Cannot resolve collation conflict for equal to operation). Sin embargo, cabe la posibilidad de utilizar la cláusula COLLATE en el JOIN, como si estuviésemos realizando un Casting (en vez de convertir entre tipos de datos, convertimos entre Intercalaciones). Así, podríamos utilizar una cláusula WHERE similar a la del siguiente ejemplo: WHERE a.client_name = b.client_name COLLATE Modern_Spanish_CI_AS.

Comentarios

Entradas populares de este blog

¿En qué puerto TCP escucha SQL Server 2005? ¿Cómo cambiar o configurar el puerto TCP de escucha de una Instancia de SQL Server 2005?

Una buena práctica inmediatamente después de instalar SQL Server 2005 es cambiar el Puerto TCP de escucha, por múltiples motivos: Seguridad, Configuración de reglas de acceso de Firewall, Aplicaciones cliente que requieren un puerto TCP estático para SQL Server, etc. En este Artículo se explica cómo averiguar en qué puerto TCP escucha SQL Server 2005, cómo cambiar el puerto TCP de escucha de SQL Server 2005, etc. Resulta de gran interés ser capaz de responder a la pregunta  ¿En qué puerto TCP escucha SQL Server?  Por defecto, una  Instancia por Defecto de SQL Server 2005  queda configurada durante la instalación para escuchar en el  puerto TCP-1433 , sin embargo,  las Instancias con Nombre  quedan configuradas durante el proceso de instalación para escuchar en  puertos TCP dinámicos , por lo tanto, cada vez que se inicie la Instancia puede que escuche en un puerto diferente. Esta situación puede resultar problemática, por un lado desde el punto de vista de la seguridad (el hecho d

¿Qué es el nivel de aislamiento (Isolation Level) de una Transacción? ¿Qué niveles de aislamiento ofrece SQL Server?

Esta capítulo explica qué es el nivel de aislamiento (isolation level) de una transacción, el comportamiento de SQL Server en operaciones de lectura o de escritura, se detallan los diferentes niveles de aislamiento basados en bloqueos (READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE) y los niveles de aislamiento basados en versionado de filas (READ COMMITTED SNAPSHOT, SNAPSHOT), se explican los males de la concurrencia (lecturas sucias, lecturas no repetibles, lecturas fantasma, y conflictos de actualización), como establecer el nivel de aislamiento deseado (SET TRANSACTION ISOLATION LEVEL y las opciones de base de datos READ_COMMITTED_SNAPSHOT y ALLOW_SNAPSHOT_ISOLATION), cómo conecer el tiempo máximo de bloqueo (@@LOCK_TIMEOUT) y como establecer el tiempo máximo de bloqueo (SET LOCK_TIMEOUT), etc. El nivel de aislamiento de una transacción (transaction isolation level)  define el grado en que se aísla una transacción de las modificaciones de recursos o datos rea

Aumentar y Reducir la TempDB en SQL Server?

Una buena práctica después de instalar SQL Server (y que interesa revisar periódicamente) es tener bien dimensionada la base de datos TEMPDB, es decir que el  tamaño inicial de TEMPDB  sea suficiente, y en consecuencia no sea necesario que TEMPDB crezca ni tampoco reducir TEMPDB (SHRINK). Esta artículo explica brevemente  para qué sirve TEMPDB , explica camo cambiar el tamaño inicial de TEMPDB (aumentar o reducir),  cómo reducir TEMPDB , cuántos ficheros son recomendables para TEMPDB, etc. ¿Para qué sirve TEMPDB?  La base de datos TEMPDB es un elemento de gran importancia en una Instancia de SQL Server, ya que  TEMPDB es la encargada de almacenar tanto los objetos temporales  (tablas temporales, procedimientos almacenados temporales, etc.),  como los resultados intermedios  que pueda necesitar crear el motor de base de datos, por ejemplo durante la ejecución de consultas que utilizan las cláusulas GROUP BY, ORDER BY, DISTINCT, etc. (es decir, las tablas temporales o WorkTables que