2008-08-15 15 views
6

Tengo una consulta donde yo estoy buscando en contra de una cadena:Base de datos de índice insensible a las mayúsculas y minúsculas?

SELECT county FROM city WHERE UPPER(name) = 'SAN FRANCISCO'; 

Ahora bien, esto funciona bien, pero no escala bien, y necesito para optimizarlo. Tengo found an option en la línea de crear una vista generada, o algo así, pero esperaba una solución más simple usando un índice.

Estamos utilizando DB2, y realmente quiero utilizar un expression in an index, pero esta opción parece estar disponible solo en z/OS, sin embargo, estamos ejecutando Linux. Probé el índice de expresión de todos modos:

CREATE INDEX city_upper_name_idx 
ON city UPPER(name) ALLOW REVERSE SCANS; 

Pero por supuesto, se ahoga en el UPPER (nombre).

¿Hay alguna otra manera en que pueda crear un índice o algo similar de esta manera para no tener que reestructurar mis consultas existentes para usar una nueva vista generada, o alterar mis columnas existentes, o cualquier otro cambio intrusivo ?

EDIT: Estoy abierto a soluciones para otras bases de datos de oír ... que podría llevar a DB2 ...

Respuesta

6

Se podría añadir una columna indexada la celebración de una clave hash numérico del nombre de la ciudad. (Con duplicados permitidos).

Posteriormente, se podría hacer un multi-cláusula where:

hash = [compute hash key for 'SAN FRANCISCO'] 

SELECT county 
FROM city 
WHERE cityHash = hash 
    AND UPPER(name) = 'SAN FRANCISCO' ; 

Otra posibilidad es ir a través de su manual de db y mirar las opciones para crear índices de tabla. Puede haber algo útil.

1

Oracle admite índices basados ​​en funciones. Su ejemplo canónico:

create index emp_upper_idx on emp(upper(ename)); 
+1

Desafortunadamente, DB2/LUW aún no lo tiene, pero probablemente provenga de que DB2/z sí lo tiene. – paxdiablo

1

PostgreSQL también soporta la indexación de los resultados de una función:

CREATE INDEX mytable_lower_col1_idx ON mytable (lower(col1)); 

La única otra opción que se me ocurre es de-normalizar sus datos un poco mediante la creación de otra columna a mantenga la versión en mayúscula (actualizada por desencadenantes) e indexe eso. ¡Blech!

+0

No necesita desencadenantes y tal, DB2 admite columnas generadas. – paxdiablo

1

No sé si esto funcionaría en DB2, pero le diré cómo lo haría en SQL Server. I think la manera en que MSSQL hace esto es estándar ANSI, aunque las cadenas de clasificación específicas pueden diferir. De todos modos, si puede hacer esto sin dañar el resto de su aplicación, ¿hay otros lugares donde la columna "nombre" debe ser sensible a mayúsculas y minúsculas? - intente hacer que toda la columna no distinga entre mayúsculas y minúsculas cambiando la intercalación, luego indexe la columna.

ALTER TABLE city ALTER COLUMN name nvarchar(200) 
    COLLATE SQL_Latin1_General_CP1_CI_AS 

... donde "nvarchar (200)" representa el tipo de datos de columna actual. La parte "CI" de la cadena de intercalación es lo que la marca como insensible a mayúsculas/minúsculas en MSSQL.

Para explicar ... mi comprensión es que el índice almacenará los valores en el orden de la intercalación de la columna indexada. Hacer que la colación de la columna sea insensible a mayúsculas/minúsculas haría que el índice almacenara 'San Francisco', 'SAN FRANCISCO' y 'san francisco' todos juntos. Entonces debería simplemente eliminar el "UPPER()" de su consulta, y DB2 debería saber que puede usar su índice.

De nuevo, esto se basa únicamente en lo que sé sobre SQL Server, más un par de minutos mirando las especificaciones SQL-92; puede o no funcionar para DB2.

1

DB2 no es fuerte con respecto a la intercalación. Y no tiene índices basados ​​en funciones.

La sugerencia de Niek Sanders funcionaría, si puede aceptar que el hashing tiene que ocurrir en su aplicación (ya que DB2 no tiene funciones SHA o MD5, hasta donde yo sé).

Sin embargo, si yo fuera usted, crearía una vista materializada (MQT == Tabla de consultas materializadas, en el lenguaje db2) utilizando CREATE TABLE AS, agregando una columna con una variante en mayúscula precalculada del nombre. Nota: Puede agregar índices a vistas materializadas en DB2.

+1

Es más económico en términos de almacenamiento y velocidad solo para agregar otra columna generada a la tabla existente en lugar de tener una tabla entera diferente. Y niego que DB2 sea débil con la intercalación. Y, el ugl de tu hermana ... lo siento, me dejé llevar :-). – paxdiablo

5

Respuesta corta, no.

Respuesta larga, sí, si está ejecutando en el mainframe, pero no lo está, por lo que debe usar otro truco.

DB2 (a partir de DB2 V8/LUW) columnas ahora se ha generado para que pueda:

CREATE TABLE tbl (
    lname VARCHAR(20), 
    fname VARCHAR(20), 
    ulname VARCHAR(20) GENERATED ALWAYS AS UPPER(lname) 
); 

y luego crear un índice en ulname. No estoy seguro de que lo vayas a simplificar.

Antes, solía tener que usar una combinación de activadores de inserción y actualización para garantizar que la columna ulname se mantuviera sincronizada, y esto era una pesadilla para mantener. Además, ahora que esta funcionalidad es parte del núcleo del DBMS, ha sido altamente optimizada (es mucho más rápida que la solución basada en disparadores) y no interfiere con los desencadenantes reales del usuario, por lo que no hay objetos DB adicionales que mantener.

Ver here para más detalles.

Cuestiones relacionadas