2010-07-30 17 views
7

que tienen una estructura de cuadro similar al siguiente:¿Equivalente a un índice compuesto en varias tablas?

create table MAIL (
    ID  int, 
    FROM  varchar, 
    SENT_DATE date 
); 

create table MAIL_TO (
    ID  int, 
    MAIL_ID int, 
    NAME  varchar 
); 

y yo tenga que ejecutar la siguiente consulta:

select m.ID 
from MAIL m 
    inner join MAIL_TO t on t.MAIL_ID = m.ID 
where m.SENT_DATE between '07/01/2010' and '07/30/2010' 
    and t.NAME = '[email protected]' 

¿Hay alguna manera de diseñar índices de tal manera que las dos condiciones se puede utilizar una ¿índice? Si pongo un índice en MAIL.SENT_DATE y un índice en MAIL_TO.NAME, la base de datos elegirá utilizar uno de los índices o el otro, no ambos. Después de filtrar por la primera condición, la base de datos siempre debe realizar un análisis completo de los resultados para la segunda condición.

+0

¿Hay alguna razón por la que no se pueda hacer una #TemTable e indexe eso en esas dos columnas? – JNK

+2

@JNK: Veo su tabla templada indexada, y le planteo una vista materializada ... –

+0

@OMG Ponies - +1, usted es el experto que acabo de pasar y repito de vez en cuando :) También ' No estoy muy familiarizado con Oracle, principalmente uso SQL Server 2008. – JNK

Respuesta

4

A materialized view le permiten indexar los valores, suponiendo que se cumplan los estrictos criterios de visualización materializada.

+0

Supongo que la aplicación tendrá que modificarse para hacer referencia a la vista materializada en su lugar? – jthg

+0

@jthg: Sí, es una vista, simplemente más rápida/más eficiente que una vista normal. –

0

¿Qué criterio es más selectivo? El rango de fechas o el destinatario? Supongo que el destinatario. Y si eso es muy selectivo, no se preocupe por el índice de fecha, simplemente deje que la base de datos haga la búsqueda en función de los ID de correo encontrados. Pero indexe la tabla MAIL en el id si no lo está ya.

Por otro lado, algunos optimizadores modernos incluso harían uso de ambos índices, escaneando ambas tablas y construyendo un valor hash de las columnas de combinación para fusionar los resultados de ambos. No estoy del todo seguro de si Oracle eligió esta estrategia. Me acabo de dar cuenta de que SQL Server tiende a hacer combinaciones de hash bastante a menudo, en comparación con otros motores.

+0

Gracias por la información. Sin embargo, no puedo ver cómo hacer una combinación de hash haría que la selección sea más rápida. Todavía tendrá que hacer un análisis completo de los resultados de cada condición. – jthg

+0

Suponía que el optimizador usaría ambos índices para restringir las dos entradas a la combinación hash. Por supuesto, los registros con el destinatario correcto y la fecha incorrecta, y viceversa, seguirían estando en las entradas de estos, pero no en los registros de otros destinatarios de MAIL_TO o del rango obsoleto de CORREO. – Frank

6

Oracle puede usar ambos índices. Simplemente no tiene el derecho dos índices.

Considere: si el plan de consulta usa primero su índice en mail.sent_date, ¿qué se obtiene al mail? Obtiene todos los mail.id s donde mail.sent_date está dentro del rango que proporcionó en su cláusula where, ¿sí?

por lo que va a mail_to con una lista de mail.id s y la mail.name que dio en su cláusula where. En este punto, Oracle decide que es mejor escanear la tabla para buscar coincidencias con mail_to.mail_id s en lugar de usar el índice en mail_to.name.

Los índices en varchar son siempre problemáticos, y Oracle realmente prefiere escaneos completos de tablas. Pero si le damos a Oracle un índice que contiene las columnas, realmente quiere que se use, y dependiendo de las filas totales de la tabla y las estadísticas, podemos conseguir que lo use. Este es el índice:

create index mail_to_pid_name on mail_to(mail_id, name) ; 

Esto funciona en un índice sólo en name no es así, ya que Oracle no está buscando sólo por un nombre, pero para un mail_id y un name.

Por el contrario, si el analizador basado en el costo determina que es más barato ir a la tabla mail_to primero, y usa su índice en mail_to.name, ¿qué se puede obtener? Un grupo de mail_to_.mail_id s para buscar en mail.Se necesita encontrar filas con los identificadores de y ciertos sent_dates, por lo que:

create index mail_id_sentdate on mail(sent_date, id) ; 

Tenga en cuenta que en este caso me he puesto sent_date por primera vez en el índice, y id segundos. (Esto es más una cosa intuitiva.)

Una vez más, el punto de referencia es este: al crear índices, debe considerar no solo las columnas en su cláusula where, sino también las columnas en sus condiciones de unión.


actualización

jthg: sí, siempre depende de cómo se distribuyen los datos. Y sobre cuántas filas hay en la tabla: si son muchas, Oracle hará un escaneo de tabla y un hash, si es muy poco hará un escaneo de tabla. Puede invertir el orden de cualquiera de los dos índices. Al poner send_date primero en el segundo índice, eliminamos la mayoría de las necesidades de un índice únicamente en sent_date.

+0

Muy bien explicado. –

+0

Gracias, pero ¿los dos índices que sugirió no serían muy útiles? El primer índice obligaría a la base de datos a probar cada MAIL_ID dentro del rango de fecha de envío, solo ahorra el tiempo de escaneo de los pocos MAIL_TO asociados con cada CORREO. El segundo índice no es diferente de un índice en solo fecha_devida, ya que no hay dos fechas_de envío serán exactamente iguales. – jthg

+2

@jthg: Oracle, como la mayoría de los motores modernos, puede hacer uso de columnas en un índice y no en una tabla evitando acceder a la tabla: Si escanea un índice y encuentra rowIds, y luego tiene que volver a el disco para buscar las páginas de la tabla que contienen estos hileras, es un gran esfuerzo, especialmente si las páginas están ampliamente distribuidas en el disco. Si la segunda columna buscada es parte del índice, se evita este acceso adicional al disco.Agregue a eso el menor tamaño de registro de los índices (normalmente, muchas menos columnas) y, por lo tanto, los datos se distribuyen en menos páginas y, por lo tanto, hay menos E/S de esta manera. – Frank

0

Si sus consultas son generalmente para un mes en particular, entonces podría partition los datos por mes.

+0

Lamentablemente, ese no es el caso. El rango es arbitrario. – jthg

Cuestiones relacionadas