2016-12-14 1 views
0

Wir haben eine kleine mobile App, die senden Sie die Teams Standorte im Feld arbeiten. Wir haben ein webbasiertes Admin-Panel, um den letzten Standort jedes Teams im Feld zu sehen, es gibt 8-10 Teams.MySQL Abfrage-Optimierung, um 8-10 Datensätze aus einer großen Tabelle zu erhalten

Jetzt die Tabelle, die die Standorte speichern, werden größer (rund 800K Datensätze) und es dauert etwa 10 Sekunden, um die Informationen aus der db zu bekommen.

Wir können die alten Aufzeichnungen nicht einfach entfernen, da wir die Geschichte der Teambesuche an verschiedenen Orten behalten möchten. in unserem Admin-Panel

In der Ansicht, wir die folgende SQL-Abfrage verwenden

SELECT w.ID, w.DaynTime, team_Desc, co_Nome, w.team_Lat, w.team_Long 
FROM (SELECT MAX(ID) AS maxID FROM VlocationTab GROUP BY UserID) AS aux 
INNER JOIN VlocationTab AS w ON w.ID = aux.maxID; 

Hier ist die Erklärung

CREATE TABLE `TableName` (
`ID` int(11) NOT NULL AUTO_INCREMENT, 
`UserID` varchar(15) NOT NULL, 
`Lat` double(8,6) NOT NULL, 
`Long` double(8,6) NOT NULL, 
`DayTime` datetime NOT NULL, 
`User` varchar(15) DEFAULT NULL, 
`Date` datetime DEFAULT NULL, 
`AUser` varchar(15) DEFAULT NULL, 
`ADate` datetime DEFAULT NULL, 
PRIMARY KEY (`ID`), 
KEY `DataTime` (`DayTime`), 
KEY `Coordenates` (`Lat`,`Long`) 
) ENGINE=MyISAM AUTO_INCREMENT=1040384 DEFAULT CHARSET=utf8; 

Gibt es trotzdem, um diese Abfrage zu optimieren, um die Ausführungszeit erstellen zu minimieren Bitte ?

+1

Haben Sie Indizes? Haben Sie versucht, EXPLAIN in Ihrer MySQL-Abfrage auszuführen? Nicht sicher, warum diese Frage mit PHP getaggt ist. – Maximus2012

+1

Siehe http://meta.stackoverflow.com/questions/333952/why-should-i-provide-an-mcve-for-what-seems-to-me-to-be-very-simple-sql- Abfrage . Gemäß dem obigen Kommentar erfordern Fragen zur Abfrageleistung immer CREATE TABLE-Anweisungen für alle relevanten Tabellen sowie EXPLAIN. – Strawberry

+0

@ Maximus2012 haben wir drei Indizes, einen auf Primärschlüssel, andere auf Datum und Uhrzeit und 3. auf Lat und Long. Versucht zu erklären, aber verstehe nicht viel. –

Antwort

1

ich bevölkern eine Testtabelle mit 1000000 Linien (1000 Benutzer und 1000 Zeilen pro Benutzer)

Hier ist der ursprüngliche Plan:

mysql> explain SELECT w.ID, w.DayTime, User, Lat, `Long` FROM (SELECT MAX(ID) AS maxID FROM TableName GROUP BY UserID) AS aux INNER JOIN TableName AS w ON w.ID = aux.maxID; 
+----+-------------+------------+------------+--------+---------------+---------+---------+-----------+---------+----------+---------------------------------+ 
| id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       | 
+----+-------------+------------+------------+--------+---------------+---------+---------+-----------+---------+----------+---------------------------------+ 
| 1 | PRIMARY  | <derived2> | NULL  | ALL | NULL   | NULL | NULL | NULL  | 1000000 | 100.00 | Using where      | 
| 1 | PRIMARY  | w   | NULL  | eq_ref | PRIMARY  | PRIMARY | 4  | aux.maxID |  1 | 100.00 | NULL       | 
| 2 | DERIVED  | TableName | NULL  | ALL | NULL   | NULL | NULL | NULL  | 1000000 | 100.00 | Using temporary; Using filesort | 
+----+-------------+------------+------------+--------+---------------+---------+---------+-----------+---------+----------+---------------------------------+ 
3 rows in set, 1 warning (0.00 sec) 

mysql> SELECT count(*) FROM (SELECT MAX(ID) AS maxID FROM TableName GROUP BY UserID) AS aux INNER JOIN TableName AS w ON w.ID = aux.maxID; 
+----------+ 
| count(*) | 
+----------+ 
|  1000 | 
+----------+ 
1 row in set (1.07 sec) 

Ihre subquery

SELECT MAX (ID) AS maxID FROM Tabellenname GROUP BY Benutzer-ID kann keinen Index verwenden, so dass Sie einen vollständigen Scan durchführen, um max (id) pro Benutzer zu suchen, und schließen Sie ihn als nächstes dem Primärschlüssel an.

Ich füge einen Index mit zwei Spalten, Benutzer und ID. Da der Index ordonned wird es ermöglichen, direkt die max (id) pro Benutzer zu erhalten:

mysql> alter table TableName add index UserID_ID(UserID,ID); 
Query OK, 1000000 rows affected (10.60 sec) 
Records: 1000000 Duplicates: 0 Warnings: 0 

neuen Plan und Zeit:

mysql> explain SELECT w.ID, w.DayTime, User, Lat, `Long` FROM (SELECT MAX(ID) AS maxID FROM TableName GROUP BY UserID) AS aux INNER JOIN TableName AS w ON w.ID = aux.maxID; 
+----+-------------+------------+------------+--------+---------------+-----------+---------+-----------+------+----------+--------------------------+ 
| id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra     | 
+----+-------------+------------+------------+--------+---------------+-----------+---------+-----------+------+----------+--------------------------+ 
| 1 | PRIMARY  | <derived2> | NULL  | ALL | NULL   | NULL  | NULL | NULL  | 1001 | 100.00 | Using where    | 
| 1 | PRIMARY  | w   | NULL  | eq_ref | PRIMARY  | PRIMARY | 4  | aux.maxID | 1 | 100.00 | NULL      | 
| 2 | DERIVED  | TableName | NULL  | range | UserID_ID  | UserID_ID | 47  | NULL  | 1001 | 100.00 | Using index for group-by | 
+----+-------------+------------+------------+--------+---------------+-----------+---------+-----------+------+----------+--------------------------+ 
3 rows in set, 1 warning (0.00 sec) 

mysql> SELECT count(*) FROM (SELECT MAX(ID) AS maxID FROM TableName GROUP BY UserID) AS aux INNER JOIN TableName AS w ON w.ID = aux.maxID; 
+----------+ 
| count(*) | 
+----------+ 
|  1000 | 
+----------+ 
1 row in set (0.04 sec) 

PS: Aber der beste Weg ist, um Ihre Anfrage zu umschreiben zu filtern am ersten Tag, zum Beispiel Zeilen jünger als einen Tag.

+0

Vielen Dank für Ihre Bemühungen, ich habe einen neuen Index für UserID und ID hinzugefügt. Es hat nicht geholfen. Dann füge ich einen Filter hinzu, (where clausel), wie Sie vorschlagen, um nur die Zeilen/Recds der letzten 2 Tage anzuzeigen, die Ausführungszeit wird auf 8 Sekunden reduziert. Was können wir sonst noch tun? –

+0

@qammarferoz - Bitte zeigen Sie uns die 'EXPLAIN' nach dem Hinzufügen dieses Index. –

Verwandte Themen