de Martin LE TARNEC

Cadenas numéricas


Las cadenas numéricas son números que se almacenan en columnas de texto. Aunque es una muy mala práctica, no deja automáticamente un índice inútil si se trata como una cadena de caracteres:

SELECT ...
  FROM ...
 WHERE numeric_string = '42'

Por supuesto, esta sentencia puede utilizar un índice sobre NUMERIC_STRING. Si se compara a un número, sin embargo, la base de datos puede no usar esa condición como un predicado de acceso.

SELECT ...
  FROM ...
 WHERE numeric_string = 42

Cuidado con potenciales acciones invisibles al usuario. Aunque algunas bases de datos producen un error (p.ej. PostgreSQL), muchas bases de datos agregan solamente una conversión implícita.

SELECT ...
  FROM ...
 WHERE TO_NUMBER(numeric_string) = 42

Es el mismo problema que antes. Un índice sobre NUMERIC_STRING no puede utilizarse debido a la función llamada. La solución es la misma que antes: no convertir la columna de la tabla; en su lugar, convertir el criterio de la búsqueda.

SELECT ...
  FROM ...
 WHERE numeric_string = TO_CHAR(42)

Se podría preguntar porqué la base de datos no lo hace así de forma automática. Es porque convertir una cadena de caracteres hacia un número da siempre resultados correctos. Eso no se aplica a la inversa. Un número, formateado en texto, puede contener espacios, puntuaciones, y tener ceros como primer carácter. Un solo valor puede escribirse de varias maneras:

42
042
0042
00042
...

La base de datos no puede saber el formato del número usado dentro de la columna NUMERIC_STRING pero sí aplica a la inversa: la base de datos convierte el número en cadena de caracteres sin problema; es una transformación sin equivocación posible.

La función TO_CHAR devuelve solamente una representación de cadenas para los números. Coincide solamente el primero de los caracteres de las cadenas listadas. Si se usa TO_NUMBER, coinciden todos ellos. Eso significa que existe no solamente una diferencia de rendimiento entre las dos variantes ¡sino también una diferencia semántica!

Usar cadenas numéricas es generalmente problemático: la mayor parte de ellas causan problemas de rendimiento debido a la conversión implícita y también introducen un riesgo de ejecución con los errores de conversiones debido a números inválidos. Aunque la sentencia sea la más trivial y no use funciones dentro del filtro where, puede causar una interrupción debido a un error de conversión solamente con que exista un número inválido almacenado en la tabla.

Sugerencia

Usa tipos numéricos para almacenar números.

Observa que el problema no existe a la inversa:

SELECT ...
  FROM ...
 WHERE numeric_number = '42'

La base de datos transformará consistentemente cadenas de caracteres hacia un número. No aplica una función sobre la columna potencialmente indexada: funcionará un índice estándar. Aun así, es posible hacer una conversión manual incorrecta:

SELECT ...
  FROM ...
 WHERE TO_CHAR(numeric_number) = '42'

Si te gusta mi manera de explicar, te encantará mi libro.

Previous pageNext page

You can’t learn everything in one day. Subscribe the newsletter via E-Mail, Twitter or RSS to gradually catch up. Have a look at modern-⁠sql.com as well.

Acerca del autor

Foto de Markus Winand

Markus Winand es defensor del resurgimiento del SQL. Su misión es la de presentar a los desarrolladores la evolución de SQL en el siglo XXI. Es posible contratar a Markus según disponibilidad o como orador o consultor en winand.at.

Adquiere tu libro

Portada de “Rendimiento SQL explicado”: Ardilla corriendo en la hierba

La esencia del tuning de SQL en 200 páginas

Compra ahora
(libro de bolsillo y/o PDF)

Contratar a Markus

La manera más rápida y fácil de beneficiarse de su extenso conocimiento y experiencia.
Aprende más »

Entrar en contacto con Markus

Markus Winand en LinkedInMarkus Winand en XINGMarkus Winand en Twitter
“Use The Index, Luke” de Markus Winand se halla bajo licencia Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Unported License.
Aspectos legales | Contacto | SIN GARANTÍA | Marcas | Privacidad y RGPD | CC-BY-NC-ND 3.0 licencia