2014-01-28 1 views
0

Я пытаюсь рассчитать и перечислить сайты в порядке наибольшего общего снижения времени отклика с одного периода на другой.SQL: Наибольшее процентное изменение во время действия ответа

Мне не нужно использовать один запрос для этого, я могу потенциально запустить несколько запросов.

сайты:

| id | url     | 
| 1 | stackoverflow.com  | 
| 2 | serverfault.com  | 
| 3 | stackexchange.com  | 

ответы:

| id | website_id | response_time | created_at | 
| 1 | 1   | 93.26   | 2014-01-28 11:51:39 
| 2 | 1   | 99.46   | 2014-01-28 11:52:38 
| 2 | 1   | 94.51   | 2014-01-28 11:53:38 
| 2 | 1   | 104.46  | 2014-01-28 11:54:38 
| 2 | 1   | 85.46   | 2014-01-28 11:56:38 
| 2 | 1   | 100.00  | 2014-01-28 11:57:36 
| 2 | 1   | 50.00   | 2014-01-28 11:58:37 
| 2 | 2   | 100.00  | 2014-01-28 11:58:38 
| 2 | 2   | 80   | 2014-01-28 11:58:39 

В идеале результат будет выглядеть следующим образом:

| percentage_change | website_id | 
| 52    | 1 | 
| 20    | 2 | 

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

SELECT * FROM websites 
LEFT JOIN (
SELECT distinct * 
     FROM responses 
     ORDER BY response_time desc) responsetable 
ON websites.id=responsetable.website_id group by website_id 

Благодаря

+0

А как вы определяя самое большое изменение в время отклика? –

+0

«Время отклика от одного периода до следующего» означает разницу между последовательными запросами или в течение определенного периода времени? Не должен ли результат для site_id = 1 в вашем примере быть 100 - ((50/104.46) * 100) = 52%? –

+0

@michalkralik Я думаю, я имею в виду, отличие от первого записанного образца до сих пор. Да, обновит образец ответа. – Tom

ответ

2

Используя пару порядковых номеров: -

SELECT a.id, a.url, MAX(100 * (LeadingResponse.response_time - TrailingResponse.response_time)/LeadingResponse.response_time) 
FROM 
(
    SELECT website_id, created_at, response_time, @aCnt1 := @aCnt1 + 1 AS SeqCnt 
    FROM responses 
    CROSS JOIN 
    (
     SELECT @aCnt1:=1 
    ) Deriv1 
    ORDER BY website_id, created_at 
) TrailingResponse 
INNER JOIN 
(
    SELECT website_id, created_at, response_time, @aCnt2 := @aCnt2 + 1 AS SeqCnt 
    FROM responses 
    CROSS JOIN 
    (
     SELECT @aCnt2:=2 
    ) Deriv2 
    ORDER BY website_id, created_at 
) LeadingResponse 
ON LeadingResponse.SeqCnt = TrailingResponse.SeqCnt 
AND LeadingResponse.website_id = TrailingResponse.website_id 
INNER JOIN websites a 
ON LeadingResponse.website_id = a.id 
GROUP BY a.id, a.url 

SQL скрипку для этого: -

http://www.sqlfiddle.com/#!2/ace08/1

EDIT - другой способ сделать это. Это будет работать, только если идентификатор в таблице ответов находится в порядке даты/времени.

SELECT a.id, a.url, MAX(100 * (r2.response_time - r1.response_time)/r2.response_time) 
FROM responses r1 
INNER JOIN responses r2 
ON r1.website_id = r2.website_id 
INNER JOIN 
(
    SELECT r1.website_id, r1.id, MAX(r2.id) AS prev_id 
    FROM responses r1 
    INNER JOIN responses r2 
    ON r1.website_id = r2.website_id 
    AND r1.id > r2.id 
    GROUP BY r1.website_id, r1.id 
) ordering_query 
ON r1.website_id = ordering_query.website_id 
AND r1.id = ordering_query.id 
AND r2.id = ordering_query.prev_id 
INNER JOIN websites a 
ON r1.website_id = a.id 
GROUP BY a.id, a.url 

Вы могли бы сделать нечто подобное на основе поля response_time, а не идентификатор, но для этого потребуется response_time для веб-сайта должен быть уникальным.

EDIT

Просто видно, что вы не просто хотите последовательных изменений, а только самого высокого до самого низкого ответа.Если предположить, что нижайший не должен прийти после того, как самые высокий: -

SELECT id, url, MAX(100 * (max_response - min_response)/max_response) 
FROM 
(
    SELECT a.id, a.url, MIN(r1.response_time) AS min_response, MAX(r1.response_time) AS max_response 
    FROM responses r1 
    INNER JOIN websites a 
    ON r1.website_id = a.id 
    GROUP BY a.id, a.url 
) Sub1 

Если вы заинтересованы только в нижнее время отклика будучи после высшего одного: -

SELECT id, url, MAX(100 * (max_response - min_following_response)/max_response) 
FROM 
(
    SELECT a.id, a.url, MAX(r1.response_time) AS max_response, MIN(r2.response_time) AS min_following_response 
    FROM responses r1 
    INNER JOIN responses r2 
    ON r1.website_id = r2.website_id 
    AND (r1.created_at < r2.created_at 
    OR (r1.created_at = r2.created_at 
    AND r1.id < r2.id)) 
    INNER JOIN websites a 
    ON r1.website_id = a.id 
    GROUP BY a.id, a.url 
) Sub1 

(при условии, что поле идентификатора на столе ответа уникально и создано по заказу)

5

Вам нужен эквивалент функции lag() или lead(). В MySQL, я делаю это с помощью коррелировала подзапрос:

select website_id, max(1 - (prev_response_time/response_time)) * 100 
from (select t.*, 
      (select t2.response_time 
       from table t2 
       where t2.website_id = t.website_id and 
        t2.created_at < t.created_at 
       order by t2.created_at desc 
       limit 1 
      ) as prev_response_time 
     from table t 
    ) t 
group by website_id; 

EDIT:

Если вы хотите, чтобы переход от самого высокого до самого низкого:

select website_id, (1 - min(response_time)/max(response_time)) * 100 
from table t 
group by website_id; 
+0

Имея некоторые проблемы с этим запуском, значения t и t2 должны быть заменены на реальные имена таблиц? Не могли бы вы бросить это в SQL Fiddle. Спасибо – Tom

+0

И t и t2 alias 'будут для таблицы ответов – Kickstart

+0

Обратите внимание, что процентный подсчет немного ошибочен. Измените его на max ((((prev_response_time - response_time)/prev_response_time)) * 100). Обратите внимание, что это зависит от уникальности даты/времени (2 строки ответа для веб-сайта с той же датой/временем будут сравниваться с ответом с предыдущим временем, а не с тем же временем, но с предыдущим идентификатором) , – Kickstart

0

группы времени отклика на website_id, найти MIN(response_time) и MAX(response_time) и сравнить ли произошло MIN() после MAX(), чтобы фильтровать только веб-сайты, которые улучшили их производительность.

<?php 
$rows = $db->fetchAll(' 
    select 
     r.website_id, min(r.response_time) min_time, max(r.response_time) max_time, 
     (select 
     rmin.created_at 
     FROM 
     responses rmin 
     WHERE 
     rmin.response_time = min(r.response_time) AND 
     rmin.website_id = r.website_id 
     ORDER BY rmin.created_at 
     LIMIT 1) min_created_at, 
     (select 
     rmax.created_at 
     FROM 
     responses rmax 
     WHERE 
     rmax.response_time = max(r.response_time) AND 
     rmax.website_id = r.website_id 
     ORDER BY rmax.created_at DESC 
     LIMIT 1) max_created_at 
    FROM 
     responses r 
    GROUP BY 
     r.website_id'); 

foreach($rows as $row) { 
    if($row['max_created_at'] < $row['min_created_at']) { 
     echo 'Website '.$row['website_id']. 
       ' improved by '. 
       (100 - (($row['min_time']/$row['max_time']) * 100)). 
       "%\n"; 
    } 
} 

Запрос будет, скорее всего, довольно медленным с большими наборами данных. Вам нужно будет оптимизировать индексы и/или запрос.
sqlfiddle: http://www.sqlfiddle.com/#!2/fa8f9/8

1

Из вашего «я получил, насколько выяснить наибольшее время отклика, но не знает, как сделать другой запрос, чтобы вычислить самое низкое время отклика, а затем сделать математику, а затем отсортировать математику «. Я понимаю, что вы хотите наименьшее время отклика и наибольшее время отклика и выполняете свою математику.

drop table #test 
create table #test(
id int, website_id int, response_time decimal, created_at datetime) 
insert into #test (id , website_id , response_time , created_at) values (1 , 1   , 93.26, '2014-01-28 11:51:39') 
insert into #test (id , website_id , response_time , created_at) values (2 , 1   , 99.46   , '2014-01-28 11:52:38') 
insert into #test (id , website_id , response_time , created_at) values (2 , 1   , 94.51   , '2014-01-28 11:53:38') 
insert into #test (id , website_id , response_time , created_at) values (2 , 1   , 104.46  , '2014-01-28 11:54:38') 
insert into #test (id , website_id , response_time , created_at) values (2 , 1   , 85.46   , '2014-01-28 11:56:38') 
insert into #test (id , website_id , response_time , created_at) values (2 , 1   , 100.00  , '2014-01-28 11:57:38') 
insert into #test (id , website_id , response_time , created_at) values (2 , 1   , 50.00   , '2014-01-28 11:58:38') 
insert into #test (id , website_id , response_time , created_at) values (2 , 2   , 100.00  , '2014-01-28 11:58:38') 
insert into #test (id , website_id , response_time , created_at) values (2 , 2   , 80   , '2014-01-28 11:58:38') 

select * from #test 
select distinct MINT.website_id,MINT.MINRT,maxT.MINRT,(MINT.MINRT/maxT.MINRT)*100--Do your calculation here--- 
from #test t0 
inner join(select min(response_time) as MINRT,website_id from #test group by website_id ) MINT 
on MINT.website_id = t0.website_id 
inner join(select max(response_time) as MINRT,website_id from #test group by website_id ) maxT 
on maxT.website_id = t0.website_id 
1

Вы хотите разделить минимальное время отклика на максимальное время отклика на сайт? Это было бы просто:

select 
    websites.id as website_id, 
    100 - min(response_time)/max(response_time) * 100 as percentage_change 
from websites 
left join responses on websites.id = responses.website_id 
group by websites.id; 

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

Смежные вопросы