2012-07-31 12 views
6

En situaciones como esta ¿qué método o combinación de métodos realiza la más rápida?Rendimiento y clasificación, y distinto único entre mysql y php

$year = db_get_fields("select distinct year from car_cache order by year desc"); 

O

$year = db_get_fields("select year from car_cache"); 
$year = array_unique($year); 
sort($year); 

He oído el distintivo en MySQL es un verdadero gran impacto en el rendimiento de consultas de gran tamaño y de esta tabla puede tener un millón o más filas. Me preguntaba qué combinación de tipos de bases de datos, Innodb o MyISAM, funcionaría mejor también. Sé que muchas optimizaciones dependen mucho de la consulta. Year es un número sin firmar, pero otros campos son de diferentes longitudes, sé que también pueden marcar la diferencia. Tales como:

$line = db_get_fields("select distinct line from car_cache where year='$postyear' and make='$postmake' order by line desc"); 

leí que con el nuevo método varias claves innodb puede realizar consultas como éste muy, muy rápido. Pero las cláusulas distinct y order by son banderas rojas para mí.

Respuesta

4

Haga que MySQL haga tanto trabajo como sea posible. Si no es eficiente en lo que está haciendo, entonces las cosas probablemente no estén configuradas correctamente (ya sea que se trate de una indexación adecuada para la consulta que está intentando ejecutar, o configuraciones con búferes de ordenación).

Si tiene un índice en la columna year, entonces usar DISTINCT debería ser eficiente. Si no lo hace, entonces es necesario un escaneo completo de la tabla para obtener las distintas filas. Si intenta clasificar las distintas filas en PHP en lugar de MySQL, entonces transmite (potencialmente) muchos más datos de MySQL a PHP, y PHP consume mucha más memoria para almacenar todos esos datos antes de eliminar los duplicados.

Aquí hay un ejemplo de salida de una base de datos de desarrollo que tengo. También tenga en cuenta que esta base de datos se encuentra en un servidor diferente en la red desde donde se ejecutan las consultas.

SELECT COUNT(SerialNumber) FROM `readings`; 
> 97698592 

SELECT SQL_NO_CACHE DISTINCT `SerialNumber` 
FROM `readings` 
ORDER BY `SerialNumber` DESC 
LIMIT 10000; 
> Fetched 10000 records. Duration: 0.801 sec, fetched in: 0.082 sec 

> EXPLAIN *above_query* 
+----+-------------+----------+-------+---------------+---------+---------+------+------+-----------------------------------------------------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref | rows | Extra              | 
+----+-------------+----------+-------+---------------+---------+---------+------+------+-----------------------------------------------------------+ 
| 1 | SIMPLE  | readings | range | NULL   | PRIMARY | 18  | NULL | 19 | Using index for group-by; Using temporary; Using filesort | 
+----+-------------+----------+-------+---------------+---------+---------+------+------+-----------------------------------------------------------+ 

Si intento la misma consulta, excepto reemplazar la columna de la SerialNumber con uno que no es indexada, entonces se necesita siempre para funcionar ya que MySQL tiene que examinar los 97 millones de filas.

Parte de la eficiencia tiene que ver con la cantidad de datos que espera recuperar. Si modifico ligeramente las consultas anteriores para operar en la columna time (la marca de tiempo de la lectura), tarda 1 min 40 segundos en obtener una lista distinta de 273,505 veces, la mayor parte de la sobrecarga que hay en la transferencia de todos los registros sobre el red. Por lo tanto, tenga en cuenta los límites de la cantidad de datos que está recuperando, y desea mantenerlos lo más bajos posible para los datos que intenta obtener.

En cuanto a su pregunta final:

select distinct line from car_cache 
where year='$postyear' and make='$postmake' 
order by line desc 

No debe haber ningún problema con que, o bien, simplemente asegúrese de que tiene un índice compuesto sobre year y make y, posiblemente, un índice en line.

En una nota final, el motor que estoy utilizando para la tabla de lecturas es InnoDB, y mi servidor es: 5.5.23-55-log Percona Server (GPL), Release 25.3 que es una versión de MySQL por Percona Inc.

Espero que ayude.

+1

Para la consulta final, el mejor índice sería '(año, marca, línea)' o '(marca, año, línea)' –

+0

excelente respuesta completa no podría pedir un mejor agradecimiento :) – Wolfe