2016-08-07 2 views
0

Ниже представлен вывод «показать полный список процессов» в командной строке my-sql. этот запрос вычисляет общую загрузку и загрузку пользователей в течение определенного периода времени. (база данных от freeradius). Как я могу сделать запрос быстрее. [Память: 150G, processr: 8 CentOS 6.8]запрос mysql, занимающий более 30 секунд

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

И ОБЪЯСНЕНИЕ? – Strawberry

+2

В любом случае, составной индекс на (acctuniqueid, radacct_id, username, acctstarttime) кажется лучшим, что можно сделать – Strawberry

+0

вы можете объяснить, что вы собираетесь достичь? Я не понимаю, почему вы хотите присоединиться к __total__ download и upload с информацией, принадлежащей одному пользователю: 'nyjohan'? – MaxU

ответ

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

И отбросьте 'KEY (username)', чтобы быть лишним. –

+0

Я бы зашел так далеко, что предложил сначала получить требуемый «radacctid» в переменную в одном запросе, а затем получить числа во втором запросе на основе этой переменной. Скорее всего, это будет не так быстро, как сделать это в одном запросе, но вы получите гораздо лучший взгляд на то, какая часть занимает столько времени. PS: исключение «actuniqueid» из запроса (что является хорошей идеей кстати) также означало бы, что вы можете оставить его вне предложенного выше составного индекса. (PPS: во избежание путаницы: я хотел сделать supra в 1 'call', а не путем получения значения клиенту, а затем запуска нового запроса для части 2 (think sp)) – deroby

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