나는 시나리오를 가지고 있었고 그것을 위해 코드를 최적화하는 훨씬 더 효율적인 방법이 있기를 바랐습니다.
ticket_thread
다음 필드로 명명 된 테이블이 있다고 가정 합니다.
모든 데이터는 ticketID, postTime 순으로 정렬됩니다.
내 일은 각 c2s에서 s2c까지 필요한 시간, 일명 응답 시간을 결정하는 것입니다.
내 현재 접근 방식은 필터링 된 테이블을 c2s 및 s2c의 두 목록으로 덤프하는 것입니다.
while (!isempty($c2s) || !isempty($s2c)) {
// popping first record from c2s
$c2sRecord = array_shift($c2s);
if (!$c2sRecord['ticketID'] == $s2c[0]['ticketID']) {
// cannot find a response to the ticket
echo $c2sRecord['ticketID'] . "<br>";
} else {
echo $c2sRecord['ticketID'];
// popping first response from s2c
$s2cRecord = array_shift($s2c);
// print out the response time
echo " " . date_diff($s2cRecord['postTime'], $c2sRecord['postTime']);
$filter = true;
while ($filter) {
// checking the next record in c2s, if it is a different ticket
// OR the new post is placed AFTER service has responded.
if (($c2s[0]['ticketID'] <> $s2cRecord['ticketID'])
or ($c2s[0]['postTime'] > $s2cRecord['postTime'])) {
// stops the filter
$filter = false;
} else {
// pop out unneeded records (supplementary questions)
$c2sRecord = array_shift($c2s);
}
}
}
내 문제는 이것이 너무 오래 걸립니다. SQL로 조작하여 필요한 것을 이와 같이 생성 할 수있는 더 빠른 방법이 있습니까?
table generated from SQL
ticket_id | c2sTime | s2cTime | timeTaken | rank
0012 | 12:20:20 | 12:30:20 | 00:10:00 | 1
0012 | 12:40:00 | 12:55:30 | 00:15:30 | 2
0012 | 13:10:20 | null | null | 3
0013 | 12:20:20 | null | null | 1
편집 : 요청 된 샘플 테이블
threadID | ticketID | threadType | postTime | message
3012 | 0012 | c2s | 12:20:20 | customer A's 1st post
3014 | 0012 | c2s | 12:20:30 | Added info to A's 1st post, should not be included
3015 | 0012 | s2c | 12:30:20 | Support responding to A's 1st post
3016 | 0012 | s2s | 12:30:30 | internal chat, should not be included
3017 | 0012 | s2s | 12:30:40 | internal chat, should not be included
3018 | 0012 | c2s | 12:40:00 | A's 2nd post
3019 | 0012 | s2c | 12:55:30 | Support responding to A's 2nd post
3020 | 0012 | s2c | 13:00:00 | Added info to Support's 2nd response, should not be included
3021 | 0012 | c2s | 13:10:00 | A's 3nd post
3013 | 0013 | c2s | 12:20:20 | customer B's 1st post
모든 창 함수 가 FILTER()
절을 지원할 수 있다면 (집계 기반 변형처럼) 작업이 훨씬 더 간단해질 수 있습니다 . 즉 모든 것 필요는 다음과 같습니다
-- won't work, unfortunately
first_value(post_time) filter (where thread_type = 's2c')
over (partition by ticket_id
order by post_time
rows between current row and unbounded following)
그때까지는 셀프 조인을 사용할 수 있습니다.
select t.*, row_number() over (partition by t.ticket_id order by t.c2s_time) rank
from (select distinct on (coalesce(s2c.thread_id, c2s.thread_id))
c2s.ticket_id,
c2s.post_time c2s_time,
c2s.message c2s_message,
s2c.post_time s2c_time,
s2c.message s2c_message,
s2c.post_time - c2s.post_time time_taken
from ticket_thread c2s
left join ticket_thread s2c on c2s.ticket_id = s2c.ticket_id
and s2c.thread_type = 's2c'
and c2s.post_time < s2c.post_time
and not exists(select 1
from ticket_thread
where post_time > c2s.post_time
and post_time < s2c.post_time
and ticket_id = c2s.ticket_id
and thread_type = 's2c')
where c2s.thread_type = 'c2s'
order by coalesce(s2c.thread_id, c2s.thread_id), c2s.post_time) t
order by t.ticket_id, t.c2s_time;
또는 array_agg()
창 기능으로 놀 수 있습니다 .
select t.*, row_number() over (partition by t.ticket_id order by t.c2s_time) rank
from (select distinct on (coalesce((m).thread_id, (t).thread_id))
(t).ticket_id,
(t).post_time c2s_time,
(t).message c2s_message,
(m).post_time s2c_time,
(m).message s2c_message,
(m).post_time - (t).post_time time_taken
from (select t, array_agg(t) filter (where thread_type = 's2c')
over (partition by ticket_id
order by post_time
rows between current row and unbounded following) a
from ticket_thread t) t
left join lateral (select m
from unnest(a) m
order by (m).post_time
limit 1) m on true
where (t).thread_type = 'c2s'
order by coalesce((m).thread_id, (t).thread_id), (t).post_time) t
order by t.ticket_id, t.c2s_time;
내 내부 테스트에서 자체 조인 변형이 조금 더 빠르며 .NET에서 인덱스를 사용할 수도 있습니다 (ticket_id, post_time)
. (그러나 성능이 정말로 중요하다면 둘 다 테스트해야합니다).
또는 누락 된 기능을 추가 할 수도 있습니다 (예 : first_agg
집계 생성 및 창 함수로 사용).
create or replace function first_agg_val(anyelement, anyelement)
returns anyelement
language sql
immutable
strict
as 'select $1';
create aggregate first_agg(
sfunc = first_agg_val,
basetype = anyelement,
stype = anyelement
);
select t.*, row_number() over (partition by t.ticket_id order by t.c2s_time) rank
from (select distinct on (coalesce((s2c).thread_id, (c2s).thread_id))
(c2s).ticket_id,
(c2s).post_time c2s_time,
(c2s).message c2s_message,
(s2c).post_time s2c_time,
(s2c).message s2c_message,
(s2c).post_time - (c2s).post_time time_taken
from (select t c2s, first_agg(t) filter (where thread_type = 's2c')
over (partition by ticket_id
order by post_time
rows between current row and unbounded following) s2c
from ticket_thread t) t
where (c2s).thread_type = 'c2s'
order by coalesce((s2c).thread_id, (c2s).thread_id), (c2s).post_time) t
order by t.ticket_id, t.c2s_time;
필요하지 않은 경우 rank
외부 쿼리를 제거 할 수 있습니다 (순전히를 위해 존재 함 rank
). (대신 클라이언트 측에서 일반적으로 계산하기 쉽습니다.)
추신 : 내 검색어의 time_taken
열은 interval
. 해당 열이 마음에 들지 않거나 파싱 할 수없는 경우 다음 수식을 대신 사용하여 초 단위 의 시간 차이를 얻을 수 있습니다 .
extract(epoch from <interval expresssion>)
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다