2012-07-31 31 views
6

In Situationen wie dieser, welche Methode oder Mischung von Methoden führt die schnellste?Leistung und Sortierung und eindeutige eindeutige zwischen mysql und php

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

Oder

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

ich die deutliche auf mysql gehört habe, ist eine wirklich große Leistungseinbußen für große Abfragen und diese Tabelle kann eine Million Zeilen oder mehr haben. Ich fragte mich, welche Kombination von Datenbanktypen, Innodb oder MyISAM, auch am besten funktionieren würde. Ich weiß, dass viele Optimierungen sehr abfrageabhängig sind. Year ist eine vorzeichenlose Zahl, aber andere Felder sind unterschiedlich lang. Ich weiß, dass das auch einen Unterschied machen kann. Wie zum Beispiel:

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

las ich, dass die neue innodb mehr Schlüssel-Methode mithilfe von Abfragen wie diese machen kann sehr sehr schnell. Aber die distinct und order by Klauseln sind rote Flags für mich.

Antwort

4

Lassen Sie MySQL so viel wie möglich arbeiten. Wenn es bei dem, was es tut, nicht effizient ist, dann sind die Dinge wahrscheinlich nicht richtig eingerichtet (ob es eine korrekte Indizierung für die Abfrage ist, die Sie ausführen möchten, oder Einstellungen mit Sortierpuffern).

Wenn Sie einen Index für die Spalte haben, sollte die Verwendung von DISTINCT effizient sein. Wenn Sie dies nicht tun, ist ein vollständiger Tabellenscan erforderlich, um die einzelnen Zeilen abzurufen. Wenn Sie versuchen, die einzelnen Zeilen in PHP anstatt in MySQL zu sortieren, dann übertragen Sie (potentiell) viel mehr Daten von MySQL nach PHP, und PHP verbraucht viel mehr Speicher, um all diese Daten zu speichern, bevor die Duplikate eliminiert werden.

Hier ist eine Beispielausgabe von einer Dev-Datenbank, die ich habe. Beachten Sie außerdem, dass sich diese Datenbank auf einem anderen Server im Netzwerk befindet, von dem aus die Abfragen ausgeführt werden.

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 | 
+----+-------------+----------+-------+---------------+---------+---------+------+------+-----------------------------------------------------------+ 

Wenn ich die gleiche Abfrage versuchen, mit Ausnahme der SerialNumber Spalte mit einer ersetzen, die nicht indiziert ist, dann dauert es ewig zu laufen, weil MySQL alle 97 Millionen Zeilen zu untersuchen hat.

Ein Teil der Effizienz hat damit zu tun, wie viele Daten Sie erwarten. Wenn ich die obigen Abfragen leicht modifiziere, um auf der time Spalte (dem Zeitstempel des Lesens) zu arbeiten, dann dauert es 1 min 40 Sekunden, um eine deutliche Liste von 273,505 mal zu erhalten, der meiste Overhead besteht darin, alle Datensätze über die zu übertragen Netzwerk. Berücksichtigen Sie daher die Grenzen für die Datenmenge, die Sie zurückerhalten, und zwar so niedrig wie möglich für die Daten, die Sie abrufen möchten.

Was Ihre letzte Abfrage:

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

Es sollte mit, dass entweder kein Problem sein, so stellen Sie sicher, dass Sie eine Verbindung Index auf year und make und möglicherweise einen Index auf line haben.

Ein letzter Punkt, der Motor I für die Lesungen Tabelle verwende ist InnoDB, und mein Server ist: 5.5.23-55-log Percona Server (GPL), Release 25.3 die

Hoffnung, eine Version von MySQL von Percona Inc. ist, das hilft.

+1

Für die endgültige Abfrage wäre der beste Index entweder '(Jahr, machen, Linie)' oder '(machen, Jahr, Linie)' –

+0

große gründliche Antwort konnte nicht besser bitten danke :) – Wolfe

Verwandte Themen