2016-12-14 10 views
0

私たちは小さなモバイルアプリケーションを持っています。各チームの最後の場所を確認するためのWebベースの管理パネルがあり、そこには8-10チームがいます。大規模なテーブルから8-10レコードを取得するためのMySQLクエリの最適化

ここでは、場所を保存するテーブルが大きくなり(約800Kレコード)、dbから情報を取得するのに約10秒かかっています。

チームの履歴を別の場所に保存したいので、単に古いレコードを削除することはできません。ビューで

、私たちはここに私たちの管理パネルで

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; 

を次のSQLクエリを使用しているステートメントを作成

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; 

で実行時間を最小限に抑えるために、このクエリを最適化するために、とにかくがありますお願いします ?

+1

インデックスはありますか? MySQLクエリで 'EXPLAIN'を実行しようとしましたか?なぜこの質問がPHPでタグ付けされているのか分かりません。 – Maximus2012

+1

http://meta.stackoverflow.com/questions/333952/why-should-i-provide-an-mcve-for-what-seems-to-me-to-be-a-very-simple-sql-クエリ さらに、上記のコメントに従って、問合せのパフォーマンスに関する問題は、常にすべての関連表とEXPLAINのCREATE TABLE文を必要とします。 – Strawberry

+0

@ Maximus2012私たちは3つのインデックスを持っています.1つはプライマリキーで、もう1つは日時で、3つ目はLatとLongです。試してみたが、あまり理解していない。 –

答えて

1

私は1000000株(千人のユーザーおよびユーザーあたり1000行)でテストテーブルを移入

ここでは、当初の計画である:

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) 

あなたのサブクエリ

SELECT MAX(ID )AS maxID From TableName GROUP BY UserID はインデックスを使用できないため、ユーザーごとにmax(id)を検索するフルスキャンを行い、次にプライマリキーと結合します。

インデックスを2つの列、userとidで追加します。

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

新しい計画と時刻::

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:インデックスがordonnedされるとして、それは直接、ユーザーごとの最大(ID)を取得することができますしかし、最良の方法は、フィルタリングするためにあなたの要求を書き換えることです例えば、1日よりも若いラインのような、最初の日付である。

+0

あなたの努力をありがとう、私はUserIDとIDの新しいインデックスを追加しました。それは助けになりませんでした。そして最後の2日間の行/履歴のみを表示するように、フィルタを追加します(where句)。実行時間を8秒に短縮します。他に何かできるの? –

+0

@qammarferoz - そのインデックスを追加した後、 'EXPLAIN'を表示してください。 –

関連する問題