ускорить самый последний запрос - PullRequest
0 голосов
/ 08 марта 2020

Я пытаюсь получить 3 успешных (успешных = 1) последних записи и затем увидеть их среднее время ответа.

Я манипулировал результатами, чтобы средний ответ всегда составлял 2 мс.

У меня сейчас 20 000 записей в этой таблице, но я планирую иметь 1-2 миллиона. Это занимает 40 секунд только с 20 000 записей, поэтому мне нужно оптимизировать этот запрос.

Вот скрипка: http://sqlfiddle.com/#! 9 / dc91eb / 1/0

Скрипка также содержит мои индексы, поэтому я могу добавить дополнительные индексы, если это необходимо.


SELECT proxy, 
       Avg(a.responsems) AS avgResponseMs,
       COUNT(*) as Count
FROM proxylog a
WHERE  
        a.success = 1 
         AND ( (SELECT Count(0) 
                FROM   proxylog b 
                WHERE  ( ( b.success = a.success ) 
                         AND ( b.proxy = a.proxy ) 
                         AND ( b.datetime >= a.datetime ) )) <= 3 ) 
GROUP  BY proxy 
ORDER BY avgResponseMs

Вот результат EXPLAIN

+----+--------------------+-------+-------+----------------+-------+---------+---------------------+-------+----------------------------------------------+
| id | select_type        | table | type  | possible_keys  | key   | key_len | ref                 | rows  | Extra                                        |
+----+--------------------+-------+-------+----------------+-------+---------+---------------------+-------+----------------------------------------------+
| 1  | PRIMARY            | a     | index | NULL           | proxy | 61      | NULL                | 19110 | Using where; Using temporary; Using filesort |
+----+--------------------+-------+-------+----------------+-------+---------+---------------------+-------+----------------------------------------------+
| 2  | DEPENDENT SUBQUERY | b     | ref   | proxy,datetime | proxy | 52      | wwwim_iroom.a.proxy | 24    | Using where; Using index                     |
+----+--------------------+-------+-------+----------------+-------+---------+---------------------+-------+----------------------------------------------+

Прежде чем вы предложите оконные функции, я Я использую MariaDB 10.1.21, который ~ Mysql 5.6 AFAIK

Ответы [ 4 ]

2 голосов
/ 08 марта 2020

Индекс на (success, proxy, datetime, responsems) должен помочь. success, proxy и datetime - это столбцы, общие для обоих запросов. datetime должно идти после двух других, потому что оно используется для фильтрации диапазона, тогда как два других - для точки. responsems идет последним, так как это столбец, по которому производится расчет. Таким образом, необходимые значения могут быть взяты непосредственно из индекса.

И, пожалуйста, отредактируйте вопрос и включите DDL и DML также в сам вопрос. Возможно, однажды скрипка сломается, и поэтому вопрос для будущих читателей бесполезен.

1 голос
/ 08 марта 2020

Я смог имитировать c row_number и следовать @Gordon Linoff answer

SELECT pl.proxy, Avg(pl.responsems) AS avgResponseMs, COUNT(*) as Count
FROM (
      SELECT 
        @row_number:=CASE
        WHEN @g = proxy 
            THEN @row_number + 1
            ELSE 1
        END AS RN,
        @g:=proxy g,
        pl.*
      FROM proxyLog pl,
      (SELECT @g:=0,@row_number:=0) as t
      WHERE pl.success = 1 
      ORDER BY proxy,datetime DESC
) pl
WHERE RN <= 3 
GROUP BY proxy 
ORDER BY avgResponseMs
0 голосов
/ 08 марта 2020

Я бы посоветовал вам попробовать написать запрос, используя оконные функции:

SELECT pl.proxy, Avg(pl.responsems) AS avgResponseMs, COUNT(*) as Count
FROM (SELECT pl.*,
             ROW_NUMBER() OVER (PARTITION BY pl.proxy ORDER BY datetime DESC) as seqnum
      FROM proxylog pl
      WHERE pl.success = 1 
     ) pl
WHERE seqnum <= 3 
GROUP BY proxy 
ORDER BY avgResponseMs;

Для этого вам нужен индекс на proxylog(success, proxy, datetime, responsems).

В более старых версиях я бы заменил ваша версия подзапроса с:

SELECT pl.proxy, Avg(pl.responsems) AS avgResponseMs, COUNT(*) as Count
FROM (SELECT pl.*,
             ROW_NUMBER() OVER (PARTITION BY pl.proxy ORDER BY datetime DESC) as seqnum
      FROM proxylog pl
      WHERE 
     ) pl
WHERE pl.success = 1 AND
      pl.datetime >= ANY (SELECT pl2.datetime
                          FROM proxylog pl2
                          WHERE pl2.success = pl.success AND
                                pl2.proxy = pl.proxy
                          ORDER BY pl2.datetime DESC
                          LIMIT 1 OFFSET 2
                         )
GROUP BY proxy 
ORDER BY avgResponseMs;

Индекс, который вы хотите для этого, такой же, как указано выше.

0 голосов
/ 08 марта 2020

От вашего комментария до моего вопроса, я думаю, я знаю, в чем ваша проблема.

Если у вас есть прокси-сервер, который имеет 900 запросов, ваш первый по-прежнему считается 900 (на уровне или выше). Второй считается 899, третий 898 и так далее. Это то, что убивает вашу производительность. Теперь добавьте, что миллионы записей приведут к тому, что ваш запрос будет лишен смысла.

То, что вы можете захотеть сделать, - это установить максимальную дату для первой, к которой вы обращаетесь, в тех случаях, когда это имеет разумный смысл. Если у вас есть запросы прокси, такие как времена (и все значения успеха)

8:00:00
8:00:18
8:00:57
9:02:12
9:15:27

Действительно ли вам важно время успеха между 8:00:57 и 9:02 и 9:15? Если компьютер набирает активность в один час, а свет в другой - действительно ли это справедливая оценка времени успеха?

То, что вы МОЖЕТЕ желать, - это иметь некоторое (по вашему усмотрению) время отключения, например, в пределах 3 минуты. Что делать, если кто-то даже не возобновляет работу через какое-то время через прокси. Это действительно так? Опять же, ваше усмотрение

 AND ( a.datetime <= b.datetime and b.datetime < date_add( a.datetime, interval 5 minutes )) )) <= 3 )

И <= 3 не дает вам того, что, я думаю, вы ожидаете. Опять же, ваш самый внутренний COUNT (*) подсчитывает все записи> = a.datetime, так что вы не получите, пока вы не дойдете до конца данного периода прокси, вы получите эти значения.

Итак Вы ищете ИСТОРИЧЕСКОЕ среднее время или только самые последние 3 временных цикла для данного прокси. То, что вы запрашиваете и запрашиваете, может быть двумя совершенно разными вещами.

Вы можете отредактировать исходное сообщение, чтобы уточнить. Я заканчиваю здесь до тех пор, пока не услышу ответ о возможном предложении дополнительной помощи.

...