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.