Pregunta

Tengo las 3 tablas siguientes en una base de datos MySQL 4.x:

  • Hospedadores: (300.000 registros)
    • id (INT SIN FIRMAR) CLAVE PRIMARIA
    • nombre (VARCHAR 100)
  • caminos: (6.000.000 registros)
    • id (INT SIN FIRMAR) CLAVE PRIMARIA
    • nombre (VARCHAR 100)
  • URL: (7.000.000 registros)
    • host (INT SIN FIRMAR) CLAVE PRIMARIA <--- enlaces a hosts.id
    • ruta (INT SIN FIRMAR) CLAVE PRIMARIA <--- enlaces a paths.id

Como puede ver, el esquema es realmente simple pero el problema es la cantidad de datos en estas tablas.

Aquí está la consulta que estoy ejecutando:

SELECT CONCAT(H.name, P.name)
FROM hosts AS H
INNER JOIN urls as U ON H.id = U.host
INNER JOIN paths AS P ON U.path = P.id;

Esta consulta funciona perfectamente bien, pero tarda 50 minutos en ejecutarse.¿Alguien tiene alguna idea sobre cómo podría acelerar esa consulta?

Gracias de antemano.Nicolás

¿Fue útil?

Solución

Para una cosa que no harían lo CONCAT en la consulta. Hacer fuera.

Pero, en realidad estás consulta se ejecuta lentamente porque estás recuperando millones de filas.

Otros consejos

Tal vez debería incluir una cláusula WHERE? O lo que realmente necesita todos los datos?

Esto me parece un caso en el que el uso excesivo de claves sustitutas te está frenando.Si las tablas fueran:

  • Hospedadores :

    • nombre (VARCHAR 100) CLAVE PRIMARIA
  • caminos :

    • nombre (VARCHAR 100) CLAVE PRIMARIA
  • URL:

    • host (VARCHAR 100) CLAVE PRIMARIA <--- enlaces a hosts.name
    • ruta (VARCHAR 100) CLAVE PRIMARIA <--- enlaces a rutas.nombre

Entonces su consulta no requeriría ninguna combinación:

SELECT CONCAT(U.host, U.path) FROM urls U;

Es cierto que las URL de las tablas ocuparían más espacio en disco, pero ¿eso importa?

EDITAR: Pensándolo bien, ¿cuál es el punto de esa tabla PATHS de todos modos?¿Con qué frecuencia diferentes hosts comparten las mismas rutas?

Por qué no:

  • Hospedadores :

    • nombre (VARCHAR 100) CLAVE PRIMARIA
  • URL:

    • host (VARCHAR 100) CLAVE PRIMARIA <--- enlaces a hosts.name
    • ruta (VARCHAR 100) CLAVE PRIMARIA <--- no hay enlace a ninguna parte

EDITAR2: O si realmente necesidad la clave sustituta para los anfitriones:

  • Hospedadores :

    • id entero CLAVE PRIMARIA
    • nombre (VARCHAR 100)
  • URL:

    • entero de host CLAVE PRIMARIA <--- enlaces a hosts.name
    • ruta (VARCHAR 100) CLAVE PRIMARIA <--- no hay enlace a ninguna parte

    Seleccione Concat (H.Name, U.Path) de las URL U UNIUD HOSTS H en H.ID = U.HOST;

En general, el mejor consejo es trazar el perfil y ver lo que realmente está tomando el tiempo. Pero aquí están mis pensamientos sobre las cosas específicas a la vista.

(1) Me gustaría decir que usted quiere asegurarse de que los índices no se utilizan en la ejecución de esta consulta. Como no tiene condiciones de filtrado, debe ser más eficiente a plena-escanear todas las tablas y luego unirlas con una operación de ordenación de combinación o hash.

(2) La concatenación de cadenas es, sin duda tomando un tiempo, pero no entiendo por qué las personas están recomendando para eliminarlo. Se podría suponer entonces que hacer la concatenación en otra pieza de código, en las que sigue a tardar alrededor de la misma cantidad de tiempo (a menos que la concatenación de cadenas de MySQL es particularmente lenta por alguna razón).

(3) La transferencia de datos desde el servidor al cliente es, probablemente, tomando un tiempo significativo, posiblemente más que el tiempo que el servidor tiene que recuperar los datos. Si dispone de herramientas para rastrear este tipo de cosas, los utilizan. Si usted puede aumentar el tamaño de recuperación matriz en su cliente, experimentar con diferentes tamaños (por ejemplo, en el uso de JDBC Statement.setFetchSize ()). Esto puede ser importante, incluso si el cliente y el servidor están en el mismo host.

Me gustaría tratar de crear una nueva tabla con los datos que desea obtener. Hacer esto significa que usted pierde algunos datos reales, pero se gana en rapidez. Esta idea podría ser similar a OLAP o algo por el estilo?

Por supuesto, usted tiene que hacer una actualización (a diario o lo que sea) de esta tabla.

No soy un experto MySQL, pero parece que las claves principales de MySQL se agrupan - usted querrá asegurarse de que es el caso con sus claves primarias; los índices agrupados sin duda ayudará a acelerar las cosas.

Una cosa, sin embargo - no creo que se pueden tener dos teclas "primarias" en cualquier mesa; su tabla de direcciones URL parece bastante sospechoso a mí por esa razón. Por encima de todo, debe estar absolutamente seguro de esas dos columnas en la tabla de direcciones URL están indexados a la empuñadura - un solo índice numérico de cada uno debe estar bien - porque se está uniendo en ellos, por lo que el DBMS necesita saber cómo encontrarlos rápidamente; eso podría ser lo que está pasando en su caso. Si eres mesa de exploración completa que muchas filas, entonces sí, podría estar sentado allí por mucho tiempo, mientras que el servidor intenta encontrar todo lo que pidió.

También me gustaría sugerir la eliminación de esa función CONCAT de la instrucción de selección, y ver cómo afecta a sus resultados. Estaría sorprendido si esto no fuera un factor que contribuye de alguna manera. Sólo recuperar ambas columnas y manejar la concatenación después, y ver cómo va.

Por último, ¿ha descubierto que el cuello de botella es? Sólo unirse en tres mesas de millones de filas varios no debería tardar mucho tiempo en absoluto (que cabe esperar tal vez un segundo o así, simplemente echando un vistazo a las tablas y consultas), siempre y cuando las tablas se indexan correctamente. Pero si usted está empujando las filas más de una tarjeta de red lenta o ya vinculado-, a un servidor de aplicaciones de memoria de hambre, etc., la lentitud podría tener nada que ver con su consulta en absoluto, pero en lugar de lo que sucede después de la consulta. Siete millones de filas es un poco de datos que se van ensamblando y moverse, independientemente de cuánto tiempo el hallazgo de esas filas pasa a tomar. Pruebe a seleccionar sólo una fila en cambio, en lugar de los siete millones de dólares, y ver cómo se ve que por el contrario. Si eso es rápido, entonces el problema no es la consulta, que es el conjunto de resultados.

A medida que el conjunto de resultados devuelve todos los datos, hay muy poca optimización que se puede hacer en absoluto. Va a escanear toda la tabla, a continuación, unirse a otras tablas que tienen índices.

se agrupan los PrimaryKeys? Esto asegura que los datos se almacenan en el disco en el orden de índice, evitando así rebotando diferentes partes del disco.

Además, puede hacer que la difusión de datos a través de múltiples discos. Si dispone de URLs en PRIMARIO y trazado / hosts en SECUNDARIA entonces obtendrá un mejor rendimiento de las unidades.

Debes mirar la configuración de tu servidor.Los parámetros de memoria predeterminados para MySQL afectarán el rendimiento en una tabla de ese tamaño.Si está utilizando los valores predeterminados, debe aumentar al menos key_buffer_size y join_buffer_size por lo menos en un factor de 4, quizás mucho más.Busque en la documentación;Hay otros parámetros de memoria que puedes modificar.

MySQL tiene una peculiaridad divertida en el rendimiento: si sus tablas superan un cierto tamaño con consultas que devolverán la mayoría de los datos, el rendimiento se va al baño.Desafortunadamente, no tiene forma de decirle cuándo se alcanza ese umbral.Pero a mí me parece que sí.

Trate de optimización de las tablas antes de ejecutar la consulta:

optimize table hosts, paths, urls;

Te puede ahorrar algo de tiempo, especialmente si las filas se han eliminado de las mesas. (Ver aquí para obtener más información acerca de optimizar)

¿Ya ha declarado algunos índices en las Join-atributos?

PS: Ver aquí [link roto] para índices en MySQL 4.x

El concat es, sin duda afectar el rendimiento. Podemos ver los resultados de un mysql explican en esto? Documentación Enlace

Lo más importante que hacer es tratar de extraer sólo los datos que necesita sin embargo. Si puede sacar un menor número de registros que acelerarán que lo más que nada. Sin embargo, un mysql explicar debería ayudarnos a ver si los índices ayudarían.

Entiendo que desea una lista completa de URL, que son 7 millones de registros.Tal vez como lo sugirió Mitch debería considerar usar la cláusula WHERE para filtrar sus resultados.Quizás el momento esté relacionado principalmente con el retraso en la visualización de los registros.

consultar hora para esta consulta

select count(*)
FROM hosts AS H
INNER JOIN urls as U ON H.id = U.host
INNER JOIN paths AS P ON U.path = P.id

Si esto sigue lento, iría y verificaría el tiempo para el recuento seleccionado (*) de las URL

entonces

select count(*) 
from urls u 
inner join hosts h on u.host = h.id

entonces

select count(*) 
from urls u 
inner join hosts h on u.host = h.id
inner join paths p on u.path = p.id

sólo para localizar la fuente de la desaceleración

También a veces reordenar tu consulta puede ayudar.

SELECT CONCAT(u.host, u.path)
from urls u 
inner join hosts h on u.host = h.id
inner join paths p on u.path = p.id

No puedo decir con certeza acerca de MySQL, pero sé que en SQL Server que las claves principales crean un índice automáticamente, pero las claves externas no lo hacen. Asegúrese de verificar que hay un índice en los campos de clave externa.

Puesto que no soy un gran fan de MySQL, preguntaría si han probado PostgreSQL. En ese DB, usted quiere asegurarse de que la configuración de work_mem era bastante alto, pero se puede establecer por conexión DB con SET work_mem = 64MB, por ejemplo.

Otra sugerencia es buscar en el uso de las entradas de ruta duplicados. Hay son muchas URL que comparten caminos.

Otra cosa que podría o no podría ayudar es el uso de los campos de texto de longitud fija en lugar de varchars. Se utiliza para hacer una diferencia de velocidad, pero no estoy seguro acerca de los actuales motores de base de datos.

Si utiliza PostgreSQL que le permitirá utilizar REGISTRARSE UTILIZANDO pero incluso en MySQL me gusta más: el nombre de su campo id igual en todas las mesas. En lugar de Identificación en los huéspedes y el anfitrión en las direcciones URL, nombre que HOST_ID ambos lugares.

Ahora, algunos más comentarios. :) Esta disposición de los datos que tenemos aquí es muy útil cuando se está seleccionando un pequeño conjunto de filas, tal vez cada URL del mismo dominio. También puede ayudar a una mucho si sus consultas a menudo tienen que hacer exploraciones secuenciales de la tabla de direcciones URL de otros datos almacenados allí, porque la exploración se puede pasar por alto los grandes campos de texto (a menos que no importa porque su texto tiendas DB a través de punteros a una tabla vinculada de todos modos).

Sin embargo, si casi siempre seleccionar todos los datos de dominio y la ruta, entonces tiene más sentido para almacenarlo en una tabla.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top