2016-09-20 8 views
1

Webトラフィックのスキーマにクエリを出して、どの訪問が初期でどのような訪問であるかを判断しています。dense_rankの最適なクエリで倍数を見つける

私は2つのテーブルSESSIONとALIASを持っています。

CREATE TABLE alias (
    person_id vachar(24), 
    alias varchar(24) 
) 

CREATE TABLE session (
    session_id vachar(24), 
    alias varchar(24) -- FK to alias 
    last_seen timestamp 
) 

セッションテーブルはエイリアスのWeb訪問を表し、エイリアステーブルには人物のエイリアスが含まれます。私はセッションのビューを作成して、最初の訪問の人物または "戻る訪問" の人物として(これは以下のエイリアスへの参加)としてセッションをマークすることができます。

私がこれまでに持っていた解決策は、以下のようにdense_rankでウィンドウ関数を使用しています。

CREATE VIEW session_augmented as (
    SELECT S.session_id, S.last_seen, .... 
    CASE 
     WHEN dense_rank() 
      OVER (partition by A.person_id COLLATE "C" ORDER by S.last_seen) = 1 
     THEN 'First Visit' 
     ELSE 'Return Visit' 
    END as visit_type 
    FROM session S 
    JOIN alias A ON (S.person_alias = A.alias) 

) 

上記の結合を含むクエリの範囲をカバーするインデックスを作成しました。

以下の説明は、person_alias列が索引付けされていても、セッションでのスキャンを示しています。以下は説明です: https://explain.depesz.com/s/2LJ

クエリは私が望むよりも遅く実行されます、最適化の方法はありますか?私は後の結果を達成するより良いアプローチはありますか?

答えて

1

ランク、デンスランク、注文に関係するものは平均値であるケースO(n log n)これは非常に大規模なデータセットに対しては非常に圧迫的になります。この場合、minという解析関数を使用することができます。この関数は、最悪で平均的なケースであるべきです。O(n)。私は、これは人がまったく同じ時間に二回にログインすることが理論的に可能であった場合は、事情のために重要疑うものの、それは二つのレコードを返すため

SELECT S.session_id, S.last_seen, .... 
CASE 
    WHEN min (S.last_seen) 
     over (partition by a.person_id) = s.last_seen 
    THEN 'First Visit' 
    ELSE 'Return Visit' 
END as visit_type 
FROM session S 
JOIN alias A ON (S.person_alias = A.alias) 

、これは失敗します。つまり、あなたのクエリは同じ問題を抱えているでしょうし、やはり私はそれが可能ではないと思います。あなたの注意を引くと思っただけです。

窓関数の価値があるのは間違いなく道のりです。私が見ている唯一の良い代替手段は、プログラミング言語でラッパーを書くことです。私はあなたがmin機能よりもはるかに改善されるとは思わない。

+0

興味深い解決策。しかし、元の質問のそれよりも実際にはそれほど速くはありませんでした。 – maxTrialfire

+0

この犯人はまだソートされています:https://explain.depesz.com/s/ZTO – maxTrialfire

+0

実際にいくつかのインデックスを追加することで、私のオリジナルのクエリを最高の状態で実行することができました:https://explain.depesz.com/s/m5E – maxTrialfire

関連する問題