2

ユーザー アクションごとの毎日のカウントと、日別およびアクションごとのさまざまなユーザー アクション レイテンシ パーセンタイルを記録するための非常に単純な Sqlite スキーマがあります。

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
)

ここでは、すべての日付が毎日の真夜中の Unix タイムスタンプとして保存されます (役に立ったら変更できます)。

ここで私が苦労しているクエリがあります: 先週の平均ボリュームで降順にソートされたアクションを表示し、50%、90%、95% レベルの平均レイテンシ パーセンタイルを含めます。私は、プランを説明するために 17 のステップを必要とする巨大なクエリを思いつきましたが、かなり遅いです。誰でも改善できますか?

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;
4

1 に答える 1

1

とテーブルのdate列にインデックスを付けたと仮定しています。action_date_countlatency_percentiles

問題は、sqlite が指定したクエリの日付インデックスを使用できないことです。これは、日付の比較を調整することで修正できます。

これの代わりに:

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

これを行う:

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

でカバリング インデックスを作成することによっても、良い結果が得られる場合がありますlatency_percentiles (date, percentile, value)。YMMV。

于 2012-11-27T12:17:22.400 に答える