8

Tengo algunas consultas que tardan demasiado (300ms) ahora que el DB ha crecido a unos pocos millones de registros. Afortunadamente para mí las consultas no necesitan ver la mayoría de estos datos, los últimos 100.000 registros serán suficientes, así que mi plan es mantener una tabla separada con los 100.000 registros más recientes y ejecutar las consultas en contra de esto. Si alguien tiene alguna sugerencia para una mejor manera de hacer esto, sería genial. Mi verdadera pregunta es, ¿cuáles son las opciones si las consultas necesitan ejecutarse contra los datos históricos? ¿Cuál es el siguiente paso? Cosas que he pensado:He golpeado el cuello de botella de rendimiento DB, ¿dónde está ahora?

  • de actualización de hardware
  • Utilice una base de datos en memoria caché
  • los objetos manualmente en su propia estructura de datos

Es esto correcto y hay alguna otra opciones? Algunos proveedores de DB tienen más funcionalidades que otros para tratar estos problemas, p. especificando una tabla/índice particular para estar completamente en la memoria?

Lo siento, debería haber mencionado esto, estoy usando mysql.

Olvidé mencionar indexación en lo anterior. La indexación ha sido mi única fuente de mejora hasta ahora para ser bastante honesto. Para identificar los cuellos de botella, he usado maatkit para que las consultas muestren si se están utilizando índices o no.

Entiendo que ahora me estoy alejando de lo que pretendía la pregunta, así que tal vez debería hacer otra. Mi problema es que EXPLAIN está diciendo que la consulta tarda 10ms en lugar de 300ms que jprofiler está informando. Si alguien tiene alguna sugerencia, realmente lo agradecería. La consulta es:

select bv.* 
from BerthVisit bv 
inner join BerthVisitChainLinks on bv.berthVisitID = BerthVisitChainLinks.berthVisitID 
inner join BerthVisitChain on BerthVisitChainLinks.berthVisitChainID = BerthVisitChain.berthVisitChainID 
inner join BerthJourneyChains on BerthVisitChain.berthVisitChainID = BerthJourneyChains.berthVisitChainID 
inner join BerthJourney on BerthJourneyChains.berthJourneyID = BerthJourney.berthJourneyID 
inner join TDObjectBerthJourneyMap on BerthJourney.berthJourneyID = TDObjectBerthJourneyMap.berthJourneyID 
inner join TDObject on TDObjectBerthJourneyMap.tdObjectID = TDObject.tdObjectID 
where 
BerthJourney.journeyType='A' and 
bv.berthID=251860 and 
TDObject.headcode='2L32' and 
bv.depTime is null and 
bv.arrTime > '2011-07-28 16:00:00' 

y la salida del EXPLAIN es:

+----+-------------+-------------------------+-------------+---------------------------------------------+-------------------------+---------+------------------------------------------------+------+-------------------------------------------------------+ 
| id | select_type | table     | type  | possible_keys        | key      | key_len | ref           | rows | Extra             | 
+----+-------------+-------------------------+-------------+---------------------------------------------+-------------------------+---------+------------------------------------------------+------+-------------------------------------------------------+ 
| 1 | SIMPLE  | bv      | index_merge | PRIMARY,idx_berthID,idx_arrTime,idx_depTime | idx_berthID,idx_depTime | 9,9  | NULL           | 117 | Using intersect(idx_berthID,idx_depTime); Using where | 
| 1 | SIMPLE  | BerthVisitChainLinks | ref   | idx_berthVisitChainID,idx_berthVisitID  | idx_berthVisitID  | 8  | Network.bv.berthVisitID      | 1 | Using where           | 
| 1 | SIMPLE  | BerthVisitChain   | eq_ref  | PRIMARY          | PRIMARY     | 8  | Network.BerthVisitChainLinks.berthVisitChainID | 1 | Using where; Using index        | 
| 1 | SIMPLE  | BerthJourneyChains  | ref   | idx_berthJourneyID,idx_berthVisitChainID | idx_berthVisitChainID | 8  | Network.BerthVisitChain.berthVisitChainID  | 1 | Using where           | 
| 1 | SIMPLE  | BerthJourney   | eq_ref  | PRIMARY,idx_journeyType      | PRIMARY     | 8  | Network.BerthJourneyChains.berthJourneyID  | 1 | Using where           | 
| 1 | SIMPLE  | TDObjectBerthJourneyMap | ref   | idx_tdObjectID,idx_berthJourneyID   | idx_berthJourneyID  | 8  | Network.BerthJourney.berthJourneyID   | 1 | Using where           | 
| 1 | SIMPLE  | TDObject    | eq_ref  | PRIMARY,idx_headcode      | PRIMARY     | 8  | Network.TDObjectBerthJourneyMap.tdObjectID  | 1 | Using where           | 
+----+-------------+-------------------------+-------------+---------------------------------------------+-------------------------+---------+------------------------------------------------+------+--------------------------------------- 

7 rows in set (0.01 sec) 
+3

¿Qué RDBMS estás usando? –

+3

¿Dónde dice EXPLAIN PLAN que el cuello de botella es para sus consultas problemáticas? –

+5

"así que mi plan es mantener una tabla separada con los 100.000 registros más recientes y ejecutar las consultas en contra de esto": parece una mala idea. –

Respuesta

1

Considerar un cambio de diseño como este no es una buena señal - Apuesto a que aún tiene mucho rendimiento para exprimir usando EXPLAIN, ajustando las variables de db y mejorando los índices y las consultas. Pero probablemente haya pasado el punto en que "probar cosas" funciona muy bien. Es una oportunidad para aprender a interpretar los análisis y registros, y usar lo que aprenda para mejoras específicas de índices y consultas.

Si su sugerencia es buena, debería poder decirnos por qué. Y tenga en cuenta que este es un pessimization-- populares

What is the most ridiculous pessimization you've seen?

3
  1. Asegúrese de que todos los índices están optimizados. Use explain en la consulta para ver si usa sus índices de manera eficiente.
  2. Si está haciendo algunas combinaciones pesadas, entonces comience a pensar en hacer este cálculo en java.
  3. Piense en usar otras bases de datos como NoSQL. Quizás puedas hacer un preprocesamiento y poner datos en Memcache para ayudarte un poco.
+0

De acuerdo. La indexación no se menciona y ofrece grandes ganancias de rendimiento en las tablas grandes: http://stackoverflow.com/questions/1108/how-does-database-indexing-work –

+0

Cambiar la base de datos no es realmente una opción para todos. – abhi

+0

No estaba diciendo cambiar la base de datos. Estaba diciendo usar otro db a datos temporales de caché. –

0

Comenzaré tratando de optimizar las tablas/índices/consultas antes de tomar cualquiera de las medidas que enumeró. ¿Ha profundizado en las consultas de bajo rendimiento hasta el punto en que está absolutamente convencido de haber alcanzado el límite de las capacidades de su RDBMS?

Editar: si está correctamente optimizado, pero aún tiene problemas, considere la posibilidad de crear una vista materializada para obtener los datos exactos que necesita. Esa puede o no ser una buena idea basada en más factores de los que usted ha proporcionado, pero lo pondría en la parte superior de la lista de cosas a considerar.

+0

Crear vista sería bueno – woliveirajr

0

Buscar en los últimos 100.000 registros debe ser terriblemente rápido, definitivamente tiene problemas con los índices. Use EXPLAIN y corríjalo.

+1

Para que quede claro, las consultas que toman 300ms están en contra de aproximadamente 9 millones en este momento. Mi idea era reducir los 9 millones a 100.000 para hacerlo más rápido – James

+0

no importa el tamaño, siempre y cuando tenga los índices correctos. si solo busca en los últimos 100.000, realmente no importa que haya 8,900,000 registros más allí. Si aún tiene dudas, publique su consulta y el esquema DB. –

1

Bueno, si usted ha optimizado la base de datos y consultas, yo diría que en lugar de la tajada de seguridad de los datos, el siguiente paso es mirar:

a) la configuración de MySQL y asegúrese de que es aprovechando al máximo el hardware

b) mira el hardware. No dices qué hardware estás usando. Puede encontrar que la replicación es una opción en su caso si puede comprar dos o tres servidores para dividir las lecturas de la base de datos (las escrituras deben realizarse en un servidor central, pero las lecturas pueden leerse desde cualquier número de esclavos) .

1

En lugar de crear una tabla separada para los últimos resultados, piense en la partición de tablas. MySQL tiene esta característica integrada en desde la versión 5,1


Sólo para que quede claro: no estoy diciendo que esta es la solución para sus problemas. Solo una cosa que puedes probar

0

Entiendo que ahora me estoy alejando de lo que la pregunta era para , así que tal vez debería hacer otra. Mi problema es que EXPLAIN dice y la consulta tarda 10 ms en lugar de 300ms que jprofiler está informando.

Entonces su problema (y solución) debe estar en Java, ¿verdad?

Cuestiones relacionadas