2016-03-22 10 views
0

私は、多数の同様のデータエントリを処理するアプリケーションのSQLベース(実際にはSQLite)ストレージを設計することに興味があります。この例では、チャットメッセージストレージにします。"データウェアハウス"のようなSQLiteストアデザイン

アプリケーションは、メッセージ参加者、タグなど、N対Nの関係を意味するすべてのデータをフィルタリングおよび分析する機能を提供する必要があります。

ので、スキーマ(スターの一種)は以下のようになります。

create table messages (
    message_id INTEGER PRIMARY KEY, 
    time_stamp INTEGER NOT NULL 
    -- other fact fields 
); 

create table users (
    user_id INTEGER PRIMARY KEY, 
    -- user dimension data 
); 

create table message_participants (
    user_id INTEGER references users(user_id), 
    message_id INTEGER references messages(message_id) 
); 

create table tags (
    tag_id INTEGER PRIMARY KEY, 
    tag_name TEXT NOT NULL, 
    -- tag dimension data 
); 

create table message_tags (
    tag_id INTEGER references tags(tag_id), 
    message_id INTEGER references messages(message_id) 
); 

-- etc. 

だから、すべての良い、よく、私はN対Nの寸法に基づいて分析操作やフィルタリングを実行する必要があるまで、 。 メッセージテーブル内の何百万行ものディメンション(この例では表示されている以上の数)があると、すべてのジョインはパフォーマンスが低下します。

例えば、私が選択したタグ、選択したユーザーおよび他の態様に基づいてフィルタリングされたデータ与えられ、各ユーザが参加したメッセージの数を分析したいと思います:

select U.user_id, U.user_name, count(1) 
from messages as M 
join message_participants as MP on M.message_id=MP.message_id 
join user as U on MP.user_id=U.user_id 
where 
    MP.user_id not in (/* some user ID's set */) 
    and M.time_stamp between @StartTime and @EndTime 
    and 
     -- more fact table fields filtering 
    and message_id in 
     (select message_id 
     from message_tags 
     where tag_id in (/* some tag ID's set */)) 
    and 
     -- more N-to-N filtering 
group by U.user_id 

私はSQLに拘束していますし、具体的には、SQLiteです。そして私はテーブルのインデックスを使用します。

私はスキーマを改善するために何か方法はないでしょうか、それを解除するための巧妙な方法でしょうか?

多分、メッセージ行内の次元キーを索引付けする方法があります(FTS機能を使用すると考えましたが、テキスト索引を検索して、結果に参加するとパフォーマンスが向上します)。

+0

正常に動作しないSQL文の例を挙げてください。 – trincot

+0

@trincot例を参照 – galenus

+0

すべての外部キーにインデックスを定義しましたか? – trincot

答えて

0

コメントが長すぎて、パフォーマンスには役立つかもしれませんが、質問に対する直接の答えではありません(スキーマは問題ありません)。

は、私はよく、多対多のために副選択フィルタのようなものを見て、私はこのような大規模なクエリに私は頻繁に実行されているから、CTEは/がwhere blag in (subselect)ではなく、参加するパフォーマンスの改善を見ることを見出した:

;with tagMesages as (
    select distinct message_id 
    from message_tags 
    where tag_id in (/* some tag ID's set */) 
) -- more N-to-N filtering 
select U.user_id, U.user_name, count(1) 
from messages as M 
join message_participants as MP on M.message_id=MP.message_id 
join user as U on MP.user_id=U.user_id 
join tagMesages on M.message_id = tagMesages.message_id 
where 
    MP.user_id not in (/* some user ID's set */) 
    and M.time_stamp between @StartTime and @EndTime 
    and 
     -- more fact table fields filtering 
group by U.user_id 

は、我々は、彼らが同じだ伝えることができますが、クエリプランナは時々、このもっと便利

免責を見つけることができます:私はSQLiteのをしない、私は、とても残念にSQL Serverを実行し、私はいくつかの明白なことを行った場合(それ以外の場合)エラーです。

+0

ありがとうございますが、[こちら](https://www.sqlite.org/lang_with.html)から理解しているように、非再帰的なCTEは読みやすくするためのものです。 – galenus

+0

@galenusはい、いいえ。これは 's.blag = a.blag'の' join(subselect)sと同じですが、これはあなたがやっていることではありません。古いa.blag in(subselect)をかなり引っ張っています。私はいつもこの場合CTEに行きますが、結合でsubselectを使用することは歓迎します。あなたのコードとは依然として大きく異なります。 – Jeff

+0

私は、SQLiteのCTEの実装がネストされたサブセレクトと同じであることを意味しています。 _join_の場合は言及したようですが、CTEの部分にはインデックスがありません。したがって、大きなデータセットの場合は、パフォーマンスがさらに悪化することが予想されます。 – galenus

関連する問題