2011-02-02 6 views
19

He tropezado con muchos campos VARCHAR (1) en una base de datos con la que recientemente tuve que trabajar. Puse los ojos en blanco: obviamente el diseñador no tenía ni idea. Pero tal vez soy yo quien necesita aprender algo. ¿Hay alguna razón concebible para usar un tipo de datos VARCHAR (1) en lugar de CHAR (1)? Yo pensaría que el RDMS se convertiría el uno al otro automáticamente.¿Hay ALGÚN sentido en el tipo de datos SQL VARCHAR (1)?

La base de datos es MS SQL 2K5, pero evolucionó desde Access en el día.

Respuesta

16

Sí, tiene sentido.

  • Más fácil para que sea definible en el idioma. Es consistente y más fácil definir varchar para permitir 1-8000 que decir que necesita ser 2+ o 3+ a 8000.

  • El aspecto VARying CHARacter de VARCHAR (1) es exactamente eso. Puede que no sea óptimo para el almacenamiento, pero transmite un significado específico, que los datos son 1 char (código de clase) o blanco (actividad externa) en lugar de NULL (desconocido/aún no clasificado).

almacenamiento juega un papel muy pequeño en este - mirando un esquema de base de datos para CHAR (1), casi se podría esperar que siempre debe tener un valor de 1 carácter, tales como tarjetas de crédito debe tener 16 dígitos. Eso simplemente no es el caso con algunos datos donde puede ser uno u opcionalmente ninguno.

También existen diferencias con el uso de la combinación VARCHAR (1) frente a CHAR (1) + NULL para los que dicen tri-estado [1-char | 0-char | NULL] es completamente inútil. Permite sentencias SQL como:

select activity + '-' + classroom 
from ... 

la que de otro modo sería más difícil si se utiliza char (1) + NULL, que puede transmitir la misma información, pero tiene diferencias sutiles.

+1

Veo que no existiría ningún motivo real para que la implementación * prohíba * VARCHAR (1), pero estoy preguntando si habría algún beneficio de diseño. Con respecto a su segundo punto, solo para aclarar, ¿está señalando que VARCHAR (1) puede ser una cadena vacía, pero CHAR (1) no puede? Puedo ver eso; una razón oscura para elegir VARCHAR (1) sobre CHAR (1), pero concebiblemente válido. –

+0

"• Más fácil de definir en el idioma". - ¿puedes elborar? –

+0

La sutileza se juega en ciertos casos de borde, 'CASE WHEN '' = ''' realmente evalúa a TRUE, es decir, espacio único = sin espacio, pero debe ser muy consciente de tales cosas. Simplemente haciendo caso omiso de un tipo de datos de mano no es realmente muy inteligente. El texto después de los dos puntos ilustra un ejemplo más sólido, que he visto en la vida real (simplemente no esas columnas específicamente). – RichardTheKiwi

10

AFAIK, No.

un VARCHAR(1) requiere almacenamiento de 3 bytes (El tamaño de almacenamiento es la longitud real de los datos introducidos + 2 bytes. Ref.

un CHAR(1) requiere 1 byte.

De una perspectiva de almacenamiento: Una regla de oro es, si es menor o igual a 5 caracteres, considere usar una columna de caracteres de longitud fija

Una razón para evitar varchar (1) (aparte del hecho de que ellos y comunicar un razonamiento deficiente del diseño, IMO) cuando se utiliza Linq2SQL: LINQ to SQL and varchar(1) fields

+3

No es una buena regla empírica. El problema con la longitud fija 4 frente a varchar (4) es que 'char (4) + '-x'' tiene espacios no deseados. Sí, puede recortar, pero eso es agregar complejidad que no se requiere simplemente usando varchar (4). – RichardTheKiwi

+0

@cyberkiwi: soy consciente de eso. Estoy hablando desde una perspectiva de almacenamiento. –

+0

No elegí que la pregunta era específicamente sobre 'almacenamiento'. Pero su edición deja más claro el alcance de su respuesta. – RichardTheKiwi

5

A varchar(1) puede almacenar una cadena de longitud cero ("vacía"). A char(1) no se puede rellenar en un solo espacio. Si esta distinción es importante para usted, puede preferir el varchar.

Aparte de eso, un caso de uso para esto puede ser si el diseñador desea permitir la posibilidad de que se requiera un mayor número de caracteres en el futuro.

Alterar un tipo de datos de longitud fija desde char(1) a char(2) significa que todas las filas de la tabla deben actualizarse y cualquier índice o restricción que acceda a esta columna cayó primero.

Hacer estos cambios en una mesa grande en producción puede ser una operación extremadamente lenta que requiere tiempo de inactividad.

modificación de una columna de varchar(1) a varchar(2) es mucho más fácil ya que es un sólo cambian los metadatos (FK limitaciones que hacen referencia tendrá que ser eliminado y recreado la columna, pero no hay necesidad de reconstruir los índices o actualizar las páginas de datos).

Además, el ahorro de 2 bytes por fila puede no siempre materializarse de todos modos. Si la definición de fila ya es bastante larga, esto no siempre afectará al número de filas que pueden caber en una página de datos. Otro caso sería si el uso de la función de compresión en Enterprise Edition de la forma en que se almacenan los datos es completamente diferente a la mencionada en la respuesta de Mitch en cualquier caso. Tanto varchar(1) como char(1) terminarían almacenados de la misma manera en la región de datos cortos.

@Thomas - por ejemplo prueba esta definición de tabla.

CREATE TABLE T2 
(
Code VARCHAR(1), 
Foo datetime2, 
Bar int, 
Filler CHAR(4000), 
PRIMARY KEY CLUSTERED (Code, Foo, Bar) 
) 

INSERT INTO T2 
SELECT TOP 100000 'A', 
        GETDATE(), 
        ROW_NUMBER() OVER (ORDER BY (SELECT 0)), 
        NULL 
FROM master..spt_values v1, master..spt_values v2 

CREATE NONCLUSTERED INDEX IX_T2_Foo ON T2(Foo) INCLUDE (Filler); 
CREATE NONCLUSTERED INDEX IX_T2_Bar ON T2(Bar) INCLUDE (Filler); 

Para una varchar es trivial para cambiar la definición de la columna de varchar(1) a varchar(2). Este es un cambio solo de metadatos.

ALTER TABLE T2 ALTER COLUMN Code VARCHAR(2) NOT NULL 

Si el cambio es char(1)-char(2) los siguientes pasos deben suceder.

  1. Suelta la PK de la tabla. Esto convierte la tabla en un montón y significa que todos los índices no agrupados deben actualizarse con el RID en lugar de la clave del índice agrupado.
  2. Alterar la definición de la columna. Esto significa que todas las filas se actualizan en la tabla para que Code ahora se almacene como char(2).
  3. Vuelva a agregar la restricción PK agrupada. Además de reconstruir el CI en sí, esto significa que todos los índices no agrupados deben actualizarse nuevamente con la clave CI como un puntero de fila en lugar de como un RID.
Cuestiones relacionadas