2009-08-07 17 views
5

Tengo una gran tabla (TokenFrequency) que tiene millones de filas en ella. La tabla TokenFrequency que se estructura como esta:SQL Alternativa para realizar una UNIÓN INTERNA en una sola tabla

Tabla - TokenFrequency

  • id - int, clave primaria
  • fuente - int, clave externa
  • símbolo - charla
  • recuento - int

Mi objetivo es seleccionar todas las filas en las que dos fuentes tienen el mismo token. Por ejemplo, si mi mesa era la siguiente:

Identificación --- --- fuente símbolo --- recuento
1 ------ --------- 1 perro - ----- 1
2 ------ 2 --------- cat -------- 2
3 ------ 3 ----- ---- cat -------- 2
4 ------ 4 --------- pig -------- 5
5 ---- - 5 --------- zoo ------- 1
6 ------ 5 --------- cat -------- 1
7 ------ 5 --------- cerdo -------- 1

Me gustaría una consulta SQL para darme la fuente 1, la fuente 2 y la suma de los recuentos. Por ejemplo:

Source1 --- --- source2 contador --- contar
---- 2 ----------- 3 --------- cat -------- 4
---- 2 ----------- 5 --------- cat -------- 3
---- 3 ----------- 5 --------- cat -------- 3
---- 4 ------- ---- 5 --------- -------- cerdo 6

tengo una consulta que tiene este aspecto:

SELECT F.source AS source1, S.source AS source2, F.token, 
     (F.count + S.count) AS sum 
FROM  TokenFrequency F 
INNER JOIN TokenFrequency S ON F.token = S.token 
WHERE F.source <> S.source 

Esta consulta funciona bien, pero los problemas que tengo con él son que:

  1. Tengo una tabla TokenFrequency que cuenta con millones de filas y por lo tanto necesitan una alternativa más rápida para obtener este resultado.
  2. La consulta actual que tengo está dando duplicados. Por ejemplo su selección:
    Source1 = 2, source2 = 3, token = gato, count = 4
    Source1 = 3, source2 = 2, token = gato, count = 4
    Lo cual no es demasiado de un problema pero si hay una manera de eludirlos y obtener un aumento de velocidad entonces sería muy útil

El principal problema que tengo es la velocidad de la consulta con mi consulta actual que lleva horas completar. El INNER JOIN en una mesa en sí mismo es lo que creo que es el problema. Estoy seguro de que tiene que haber una forma de eliminar la unión interna y obtener resultados similares simplemente usando una instancia de la tabla TokenFrequency. El segundo problema que mencioné también podría promover un aumento de velocidad en la consulta.

Necesito una forma de reestructurar esta consulta para proporcionar los mismos resultados de una manera más rápida y eficiente.

Gracias.

+1

Puede publicar el EXPLAIN de la consulta (http://dev.mysql.com/doc/refman/5.0/en/explain.html). Ayudará a la gente a ver cómo pueden ayudarlo a optimizar. –

+0

necesita dar alguna información de índice, qué columnas, etc. –

+0

Aquí está mi EXPLICACIÓN de la consulta que publiqué inicialmente. id: 1, tipo_selección: SIMPLE, tabla: F & S, tipo: ALL, Possible_keys: NULL, Key: NULL, Key_len: NULL, ref: NULL, rows: 8, Extra: Using where; Usando el buffer de unión Se han devuelto dos filas, la única diferencia son los dos nombres de tabla F y S. – cruzja

Respuesta

2

que iba a necesitar un poco más de información para diagnosticar el problema de velocidad, pero para eliminar los DUP, añadir a la DONDE:

AND F.source<S.source 
+0

Ah tan simple. Esto funcionó perfectamente para eliminar los duplicados. Gracias – cruzja

2

Prueba esto:

SELECT token, GROUP_CONCAT(source), SUM(count) 
FROM TokenFrequency 
GROUP BY token; 

Esto debería funcionar mucho más rápido y también elimina los duplicados. Pero las fuentes se devolverán en una lista separada por comas, por lo que tendrá que explotar eso en su aplicación.

También puede intentar crear un índice compuesto sobre las columnas token, source, count (en ese orden) y analizar con EXPLAIN para ver si MySQL es lo suficientemente inteligente como para utilizarlo como un covering index para esta consulta.

actualización

: que parecen haber entendido mal su pregunta. No desea la suma de conteos por token, quiere la suma de los conteos por cada par de fuentes para un token dado.

Creo que la unión interna es la mejor solución para esto. Una guía importante para SQL es que si necesita calcular una expresión con respecto a dos filas diferentes, entonces necesita hacer una combinación.

Sin embargo, una técnica de optimización que mencioné anteriormente es usar cubriendo el índice para que todas las columnas que necesita estén incluidas en una estructura de datos de índice. El beneficio es que todas sus búsquedas son O (log n), y la consulta no necesita hacer una segunda E/S para leer la fila física para obtener otras columnas.

En este caso, debe crear el índice de cobertura sobre las columnas token, source, count como mencioné anteriormente. También intente asignar suficiente espacio de caché para que el índice pueda guardarse en la memoria.

+1

+1 por el enfoque correcto; pero tal índice sería casi tan grande como todo el registro, ¿crees que sería más rápido que solo indexar en token? – Javier

+0

Depende del número de filas y otros factores específicos del sistema. La única manera de estar seguro es probarlo con * su * base de datos y medir el rendimiento. –

+0

Este es un buen enfoque pero el único problema que crea si tienes un token que está en más de una fuente, entonces obtienes todos esos casos juntos.Por ejemplo, en mi caso de ejemplo, el token "cat" está en la fuente 2,3 y 5, por lo que me da un conteo de 5 en lugar de darme 2 y 3 con un recuento de 4, 3 y 5 con un recuento de 3 y 2 y 5 con un conteo de 3. En mi conjunto de datos real y grande hay tokens que aparecen en casi todos los documentos que me darían GROUP_CONCAT de miles de fuentes y su respectivo conteo. – cruzja

1

Si token no está indexado, ciertamente debe ser.

Cuestiones relacionadas