2012-04-12 5 views
2

ich ein ziemlich einfaches SQLite-Schema für durch Benutzeraktionen und verschiedene Benutzeraktion Latenz Perzentile bei Tag und Aktion täglich zählt die Aufnahme:Optimierung SQLite Abfrage: Gruppierung in Subqueries

create table user_actions (
    id integer primary key, 
    name text not null 
) 

create table action_date_count (
    action_id integer not null 
    references user_actions(id) on delete restrict on update restrict, 
    date integer not null, 
    count integer not null, 
    unique (action_id, date) on conflict fail 
) 

create table latency_percentiles (
    action_id integer not null 
    references user_actions(id) on delete restrict on update restrict, 
    date integer not null, 
    percentile integer not null, 
    value real not null, 
    unique (action_id, date, percentile) on conflict fail 
) 

Hier wird alle Daten werden als Unix-Zeitstempel gespeichert von Mitternacht eines jeden Tages (ich kann das ändern, wenn es hilft).

Jetzt ist hier eine Abfrage, mit der ich kämpfe: zeigen Aktionen nach dem durchschnittlichen Volumen in der letzten Woche absteigend sortiert, enthalten durchschnittliche Latenz Perzentile bei 50%, 90%, 95% Ebenen. Ich habe eine riesige Frage gestellt, die erklärt, dass der Plan sagt, dass es 17 Schritte dauert, und es ist ziemlich langsam. Kann jemand es verbessern?

select ua.id, ua.name, ac.avg_count, al50.avg_lat_50, al90.avg_lat_90, al95.avg_lat_95 
    from 
    user_actions as ua, 
    (
     select adc.action_id as action_id, avg(adc.count) as avg_count 
     from 
     action_date_count as adc, 
     (select max(date) as max_date from action_date_count) as md 
     where 
     julianday(md.max_date, 'unixepoch', 'localtime') - julianday(adc.date, 'unixepoch', 'localtime') between 1 and 7 
     group by action_id 
    ) as ac, 
    (
     select lp.action_id as action_id, avg(lp.value) as avg_lat_50 
     from 
     latency_percentiles as lp, 
     (select max(date) as max_date from action_date_count) as md 
     where 
     lp.percentile = 50 and 
     julianday(md.max_date, 'unixepoch', 'localtime') - julianday(lp.date, 'unixepoch', 'localtime') between 1 and 7 
     group by action_id 
    ) as al50, 
    (
     select lp.action_id as action_id, avg(lp.value) as avg_lat_90 
     from 
     latency_percentiles as lp, 
     (select max(date) as max_date from action_date_count) as md 
     where 
     lp.percentile = 90 and 
     julianday(md.max_date, 'unixepoch', 'localtime') - julianday(lp.date, 'unixepoch', 'localtime') between 1 and 7 
     group by action_id 
    ) as al90, 
    (
     select lp.action_id as action_id, avg(lp.value) as avg_lat_95 
     from 
     latency_percentiles as lp, 
     (select max(date) as max_date from action_date_count) as md 
     where 
     lp.percentile = 95 and 
     julianday(md.max_date, 'unixepoch', 'localtime') - julianday(lp.date, 'unixepoch', 'localtime') between 1 and 7 
     group by action_id 
    ) as al95 
    where ua.id = ac.action_id and ua.id = al50.action_id and ua.id = al90.action_id and ua.id = al95.action_id 
    order by ac.avg_count desc; 

Antwort

1

Ich gehe davon aus Sie die date Spalten auf action_date_count und latency_percentiles Tabellen indiziert.

Das Problem ist, dass sqlite den Datumsindex bei der von Ihnen angegebenen Abfrage nicht verwenden kann. Sie können dies beheben, indem Sie Ihre Datumsvergleiche anpassen.

Statt dessen:

julianday(md.max_date, 'unixepoch', 'localtime') - julianday(lp.date, 'unixepoch', 'localtime') between 1 and 7 

tun:

lp.date between md.max_date - 7 * 24 * 3600 and md.max_date 

Sie können auch gute Ergebnisse erzielen, indem ein abdeckenden Index auf latency_percentiles (date, percentile, value) zu schaffen. YMMV.