¿CHAR o VARCHAR? ¿cuál es mejor?

4 comentarios

Cuando declaras una columna alfanumérica puedes elegir entre CHAR y VARCHAR. ¿Cuál de esos tipos de datos es mejor?

Guardando columnas CHAR en .DBF y en Paradox

En las tablas .DBF y en las tablas de Paradox, si declaras una columna como CHAR y guardas en esa columna menos caracteres que los declarados se la completa con espacios en blanco.

Ejemplo:

Si una columna de una tabla .DBF está declarada como CHAR(20) y guardas en esa columna:

‘HOLA’, se le agregan 16 espacios en blanco, para completar los 20 declarados

‘ASUNCIÓN’, se le agregan 12 espacios en blanco para guardar los 20 declarados

‘AMERICA’ se le agregan 13 espacios en blanco para completar los 20 declarados

Guardando columnas CHAR en Firebird

Firebird no agrega espacios en blanco al final porque cuando se guarda una fila, la fila completa (con todas sus columnas CHAR, VARCHAR, INTEGER, DATE, TIME, etc.) es comprimida usando el algoritmo RLE.

Se hace así para ahorrar espacio en el disco duro porque la fila comprimida ocupa menos espacio que la fila sin comprimir.

Ejemplo:

Una columna de una tabla Firebird está declarada como CHAR(20) y guardas en esa columna:

‘HOLA’, ocupa 4 caracteres

‘ASUNCIÓN’, ocupa 8 caracteres

‘AMÉRICA’, ocupa 7 caracteres

Como puedes ver Firebird solamente guarda los datos significativos, no agrega espacios en blanco al final.

Guardando columnas VARCHAR en Firebird

Las columnas de tipo VARCHAR ocupan 2 bytes más que los declarados porque se usan 2 bytes para conocer la longitud de la cadena guardada.

Ejemplo:

Una columna de una tabla Firebird está declarada como VARCHAR(20) y guardas en esa columna:

‘HOLA’, ocupa 6 caracteres (2 que indican la longitud más 4 de la palabra ‘HOLA’)

‘ASUNCIÓN’, ocupa 10 caracteres (2 que indican la longitud más 8 de la palabra ‘ASUNCIÓN’)

‘AMÉRICA’, ocupa 9 caracteres (2 que indican la longitud más 7 de la palabra ‘AMÉRICA’)

Ahorrando espacio en el disco duro

Si lo que necesitas es ahorrar espacio en el disco duro entonces CHAR es más eficiente que VARCHAR porque como has visto cada columna CHAR ocupa 2 bytes menos que su correspondiente columna VARCHAR.

Espacio ocupado en la memoria RAM

En ambos casos la columna ocupa el espacio declarado.

Ejemplo:

Una columna CHAR(20) ocupa 20 bytes en la memoria RAM

Una columna VARCHAR(20) ocupa 20 bytes en la memoria RAM

Consultando columnas CHAR y VARCHAR

Cuando ejecutas un comando SELECT sobre una columna CHAR Firebird le agrega los espacios en blanco necesarios para completar la longitud declarada.

Cuando ejecutas un comando SELECT sobre una columna VARCHAR Firebird ignora a los dos primeros caracteres (los que indican la longitud) y devuelve el resto de la cadena.

Por lo tanto, al usar CHAR se ahorran 2 bytes pero al hacer el SELECT de esa columna se pierde tiempo en rellenarla con los espacios en blanco faltantes.

Decidiendo entre CHAR y VARCHAR

Como hemos visto, al declarar una columna como CHAR se ahorra espacio en el disco duro (2 bytes menos que si la declaramos como VARCHAR) pero las consultas que involucran a columnas CHAR son más lentas que las que involucran a columnas VARCHAR porque las columnas CHAR deben ser rellenadas con espacios en blanco antes de ser mostradas.

Esos 2 bytes que se ahorran al declarar a la columna como CHAR, en esta época y con los discos duros gigantescos disponibles, pueden ser irrelevantes y no degradarán el rendimiento de la Base de Datos. La excepción es cuando la cantidad de caracteres a almacenar es pequeña, por ejemplo declarar una columna como VARCHAR(3) es un error porque en realidad se guardan en el disco duro 5 bytes (2 de la longitud más 3 declarados)  cuando usando CHAR(3) solamente necesitaríamos 3 bytes y además al ser la longitud tan pequeña (sólo 3 bytes) VARCHAR no sería más rápido que CHAR.

Por lo tanto:

  • Si la cantidad de caracteres a guardar en una columna es fija y menor que 80, usar CHAR
  • Si la cantidad de caracteres a guardar en una columna es fija o es variable y esa cantidad es menor o igual que 10, usar CHAR
  • Si la cantidad de caracteres a guardar en una columna es variable y es mayor que 10, usar VARCHAR
  • Si la cantidad de caracteres a guardar en una columna es variable y mayor que 10.000 suele ser preferible usar un BLOB de texto

Ejemplos donde se debería usar CHAR

  • Guardar el código del Estado (‘AK’, ‘AZ’, ‘NY’, ‘SC’, ‘TX’). Todos los códigos tienen 2 caracteres
  • Guardar el sexo (‘F’, ‘M’). Todos tienen 1 caracter
  • Guardar el prefijo telefónico (‘021’, ‘022’, ‘028’, ‘0293’). Todos los prefijos tienen 3 caracteres ó 4 caracteres

Ejemplos donde se debería usar VARCHAR

  • Guardar el nombre de la persona (‘ANA PAULA’, ‘CYNTHIA ELIZABETH’, ‘PATRICIA ADRIANA’). La cantidad de caracteres es variable
  • Guardar la dirección del proveedor (‘COLÓN 1234’, ‘HERNANDARIAS 3455’, ‘ESTADOS UNIDOS 56789’). La cantidad de caracteres es variable

Artículo relacionado:

El índice del blog Firebird21

Anuncios

Consultando datos que NO EXISTEN en una tabla

1 comentario

En las consultas lo normal es responder preguntas positivas, por ejemplo: ¿qué productos se vendieron hoy? ¿a cuáles clientes se les cobró hoy? ¿cuáles vendedores hicieron ventas hoy?

Todas esas preguntas son positivas porque los datos están guardados en las tablas y para responderlas lo que hacemos es consultar datos que se guardaron en las tablas.

Pero a veces necesitamos responder preguntas negativas, por ejemplo: ¿cuáles productos NO se vendieron hoy? ¿a cuáles clientes NO se les cobró hoy? ¿cuáles vendedores NO hicieron ventas hoy?

En Matemática, en la teoría de conjuntos, a esto se le llama “diferencia de conjuntos” y en Firebird tenemos dos formas de conseguirlo:

  1. Negamos la función EXISTS() para hallar la diferencia entre dos conjuntos
  2. Escribimos un LEFT JOIN y un NULL en la cláusula WHERE

Ejemplo:

Tenemos una tabla llamada PRODUCTOS que tiene estas filas:

DIFERENCIA1

Captura 1. Si haces clic en la imagen la verás más grande

y una tabla llamada MOVIMDET (detalles de los movimientos) que tiene estas filas:

DIFERENCIA2

Captura 2. Si haces clic en la imagen la verás más grande

donde en la columna MOV_IDEPRD se guarda el identificador del producto. Usamos esa columna para relacionar ambas tablas.

Método 1

Para saber cuales fueron los productos que NO SE VENDIERON escribimos esta consulta:

SELECT
   PRD_IDENTI,
   PRD_NOMBRE
FROM
   PRODUCTOS P
WHERE
   NOT EXISTS(SELECT
                 M.MOV_IDEPRD
              FROM
                 MOVIMDET M
              WHERE
                 M.MOV_IDEPRD = P.PRD_IDENTI)

y obtenemos este resultado:

DIFERENCIA3

Captura 1. Si haces clic en la imagen la verás más grande

donde como puedes ver se encuentran los productos que NO ESTÁN en la tabla MOVIMDET. En la tabla MOVIMDET los productos tienen los identificadores: 13, 14, 15, 16 y ningún producto con alguno de esos identificadores es mostrado en el resultado que obtuvimos.

Método 2

Podríamos obtener exactamente el mismo resultado escribiendo:

SELECT
   PRD_IDENTI,
   PRD_NOMBRE
FROM
   PRODUCTOS P
LEFT JOIN
   MOVIMDET M
      ON P.PRD_IDENTI = M.MOV_IDEPRD
WHERE
   M.MOV_IDEPRD IS NULL

Conclusión:

Con Firebird podemos responder preguntas positivas y preguntas negativas, hay que conocer las técnicas para responder las preguntas negativas porque pueden sernos útiles muchas veces.

Artículos relacionados:

Teoría de Conjuntos: Unión, Intersección, Diferencia

El índice del blog Firebird21