下面是my-sql命令行上“show full processlist”的输出。此查询计算指定时间段内的用户总上载和下载带宽。 (数据库来自freeradius)。如何更快地进行查询? [记忆:150G,处理器:8 centos 6.8]
15260415|radiusremote|panel.example.com:57526|radius|Query|35|Copying to tmp table
SELECT sum(acctinputoctets) as upload,sum(acctoutputoctets) as download
FROM radacct a
INNER JOIN
( SELECT acctuniqueid, MIN( radacctid ) radacctid
FROM radacct
WHERE username='nyjohan'
and acctstarttime between '2016-01-15 13:50:05'
AND '2016-08-07 13:16:36'
GROUP BY acctuniqueid
) b ON a.acctuniqueid = b.acctuniqueid
AND a.radacctid = b.radacctid
表上创建了索引,下面是表
上的索引输出mysql> show index from radacct;
+---------+------------+-----------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+---------+------------+-----------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+
| radacct | 0 | PRIMARY | 1 | radacctid | A | 161791738 | NULL | NULL | | BTREE | |
| radacct | 1 | username | 1 | username | A | 15 | NULL | NULL | | BTREE | |
| radacct | 1 | framedipaddress | 1 | framedipaddress | A | 458333 | NULL | NULL | | BTREE | |
| radacct | 1 | acctsessionid | 1 | acctsessionid | A | 161791738 | NULL | NULL | | BTREE | |
| radacct | 1 | acctsessiontime | 1 | acctsessiontime | A | 46332 | NULL | NULL | YES | BTREE | |
| radacct | 1 | acctuniqueid | 1 | acctuniqueid | A | 161791738 | NULL | NULL | | BTREE | |
| radacct | 1 | acctstarttime | 1 | acctstarttime | A | 40447934 | NULL | NULL | YES | BTREE | |
| radacct | 1 | acctstoptime | 1 | acctstoptime | A | 80895869 | NULL | NULL | YES | BTREE | |
| radacct | 1 | nasipaddress | 1 | nasipaddress | A | 15 | NULL | NULL | | BTREE | |
+---------+------------+-----------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+
表的架构
mysql> describe radacct;
+----------------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+-------------+------+-----+---------+----------------+
| radacctid | bigint(21) | NO | PRI | NULL | auto_increment |
| acctsessionid | varchar(32) | NO | MUL | | |
| acctuniqueid | varchar(32) | NO | MUL | | |
| username | varchar(64) | NO | MUL | | |
| groupname | varchar(64) | NO | | | |
| realm | varchar(64) | YES | | | |
| nasipaddress | varchar(15) | NO | MUL | | |
| nasportid | varchar(15) | YES | | NULL | |
| nasporttype | varchar(32) | YES | | NULL | |
| acctstarttime | datetime | YES | MUL | NULL | |
| acctstoptime | datetime | YES | MUL | NULL | |
| acctsessiontime | int(12) | YES | MUL | NULL | |
| acctauthentic | varchar(32) | YES | | NULL | |
| connectinfo_start | varchar(50) | YES | | NULL | |
| connectinfo_stop | varchar(50) | YES | | NULL | |
| acctinputoctets | bigint(20) | YES | | NULL | |
| acctoutputoctets | bigint(20) | YES | | NULL | |
| calledstationid | varchar(50) | NO | | | |
| callingstationid | varchar(50) | NO | | | |
| acctterminatecause | varchar(32) | NO | | | |
| servicetype | varchar(32) | YES | | NULL | |
| framedprotocol | varchar(32) | YES | | NULL | |
| framedipaddress | varchar(15) | NO | MUL | | |
| acctstartdelay | int(12) | YES | | NULL | |
| acctstopdelay | int(12) | YES | | NULL | |
| xascendsessionsvrkey | varchar(10) | YES | | NULL | |
+----------------------+-------------+------+-----+---------+----------------+
解释输出: -
explain SELECT sum(acctinputoctets) as upload,sum(acctoutputoctets) as download
FROM radacct a
INNER JOIN (
SELECT acctuniqueid, MIN( radacctid ) radacctid
FROM radacct
WHERE username='dave137' and acctstarttime between '2016-08-03 00:00:00' and '2016-08-07 14:47:54' GROUP BY acctuniqueid
)b ON a.acctuniqueid = b.acctuniqueid
AND a.radacctid = b.radacctid ;
+----+-------------+------------+--------+------------------------+----------+---------+-------------+-------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+--------+------------------------+----------+---------+-------------+-------+----------------------------------------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 10 | |
| 1 | PRIMARY | a | eq_ref | PRIMARY,acctuniqueid | PRIMARY | 8 | b.radacctid | 1 | Using where |
| 2 | DERIVED | radacct | ref | username,acctstarttime | username | 66 | | 10164 | Using where; Using temporary; Using filesort |
+----+-------------+------------+--------+------------------------+----------+---------+-------------+-------+----------------------------------------------+
3 rows in set (9.91 sec)
答案 0 :(得分:3)
对于此查询:
SELECT sum(acctinputoctets) as upload,sum(acctoutputoctets) as download
FROM radacct a INNER JOIN
(SELECT acctuniqueid, MIN( radacctid ) as radacctid
FROM radacct
WHERE username = 'dave137' and acctstarttime between '2016-08-03 00:00:00' and '2016-08-07 14:47:54'
GROUP BY acctuniqueid
) b
ON a.acctuniqueid = b.acctuniqueid AND a.radacctid = b.radacctid ;
我建议使用两个索引,一个已经存在:radacct(radacctid)
和radacct(username, acctstarttime, acctuniqueid)
。
此外,我会将ON
子句简化为:
ON a.radacctid = b.radacctid ;
radacctid
是唯一的,因此不需要其他条件。
答案 1 :(得分:1)
在子查询中使用JOIN会降低查询速度,无论索引如何。从我所看到的,这应该做同样的事情而不需要进行子连接:
SELECT acctinputoctets as upload, acctoutputoctets as download
FROM radacct a
WHERE username = 'dave137'
and acctstarttime between '2016-08-03 00:00:00' and '2016-08-07 14:47:54'
ORDER BY radacctid
LIMIT 1