2016-04-20 6 views
0
CREATE TABLE campaigns (
    domain varchar(50) DEFAULT NULL, 
    campaign_id varchar(50) DEFAULT NULL, 
    node_id varchar(50) DEFAULT NULL, 
    subscriber_id varchar(50) DEFAULT NULL, 
    message varchar(21000) DEFAULT NULL, 
    log_time datetime DEFAULT NULL, 
    log_type varchar(50) DEFAULT NULL, 
    campaign_name varchar(500) DEFAULT NULL 

    KEY `campid_domain_logtype_logtime_subid_index` (`campaign_id`,`domain`,`log_type`,`log_time`,`subscriber_id`), 
    KEY `domain_logtype_logtime_index` (`domain`,`log_type`,`log_time`) 

) 

上記はMySqlのテーブルのスキーマです。 1つのキャンペーンは複数のノードを持つことができます。MySqlが複合インデックスを処理する方法

インデックスcampid_domain_logtype_logtime_subid_indexは、レポートw.r.tの特定のキャンペーンで問題なく動作します。

最近このノードにnode_idを追加しました。これで特定のノードのレポートが必要になりました。だから今

私はキャンペーンレベルとノード・レベルの両方をサポートするために、次のように私たちの被覆率が変化するつもりは

campid_nodeid_domain_logtype_logtime_subid_indexを報告します。特定のキャンペーンの特定のノードIDでのレポートの特定のキャンペーン

SELECT log_type, 
     count(DISTINCT subscriber_id) AS count, 
     count(subscriber_id) AS total 
FROM stats.campaign_logs USE INDEX(campid_domain_logtype_logtime_subid_index) 
where domain = 'aaa' AND campaign_id='12345' AND 
    log_type in ('EMAIL_SENT','EMAIL_OPENED','EMAIL_CLICKED') 
    AND log_time BETWEEN CONVERT_TZ('2016-03-13 00:00:00','+01:30','+00:00') AND CONVERT_TZ('2016-04-13 23:59:59','+01:30','+00:00') 
GROUP BY log_type; 

例のクエリについてのレポートのための

例クエリ

SELECT 
    log_type, 
    count(DISTINCT subscriber_id) AS count, 
    count(subscriber_id) AS total 
FROM stats.campaign_logs USE INDEX(campid_domain_logtype_logtime_subid_index) 
where domain='aaa' AND campaign_id='12345' AND 
     node_id = '56789' and 
     log_type in ('EMAIL_SENT','EMAIL_OPENED','EMAIL_CLICKED') 
     AND log_time BETWEEN CONVERT_TZ('2016-03-13 00:00:00','+01:30','+00:00') AND CONVERT_TZ('2016-04-13 23:59:59','+01:30','+00:00') 
GROUP BY log_type; 

だから私の質問は、この新しい指標は、効果的にクエリの私たちのようなものの両方を満足さありませんそうでない場合は、適切なインデックスを提案してください。

UPDATE:表の

データ分布

1ドメイン20

1キャンペーンが

1キャンペーンを有することができ、例えば10複数のノードを持つことができ、例えば、複数のキャンペーンを有することができますたとえば複数のログタイプ50

1キャンペーンcan ha多くのユーザなど100,000

1ログを保存するときにmysql now()を使用するため、キャンペーンのログ時間が長くなることがあります。

UPDATE

おかげ

答えて

0

クエリをよると、あなただけのいくつかのケースで

KEY `campid_domain_logtype_logtime_subid_index` (
    `campaign_id`, 
    `domain`, 
    `log_time`, 
    `node_id`, 
    `subscriber_id` 
); 

campaign_idlog_timeが常に使用されている以下のインデックス、node_idを作成する必要があります。あなたは、クエリにそれらのすべてを参照してくださいしないでくださいdomainsubscriber_id

を左にする必要があること

わかりません。

log_typeも議論の対象です。私はそれが良い選択性を持っていると信じていないだけのスペースを無駄にします。

を更新しました私たちのコミュニケーションを従えばコメントで

  • キャンペーンIDは
  • ドメインが第二である主要な柱です。それを追加 - 多分あなたはあなたのため
  • ノードIDを選択する範囲のためにそれに特定のクエリ

あなたは、多くの場合、クエリでSUBSCRIBER_IDを使用している場合を

  • ログの時間を削除する必要があり、再生しよう。

    そしてlog_typeを削除します。

    オプションとして、以下のインデックスを作成しよう:最高のインデックス構築するための

    Campaign id, Log time, Node ID (subscriber_id ?) 
    
  • +0

    各フィールドの選択性を追加できますか?ユニークな値はどれくらいですか –

    +0

    テーブルにはどのくらいのドメインがありますか? –

    +0

    今はarround 4kです。いくつかのドメインはわずかな行しか持たず、いくつかのドメインはテーブルの行数が多いです。 – Rams

    0

    基本ルール:

    1. は、任意の順序で、 '=' でのカラム(複数可)を含めます。
    2. は、1つの他のカラム、好ましくは範囲を含む。

    最初のクエリにはINDEX(domain, campaign_id, log_time)が必要です。 log_typeは途中で取得します。それを含めないでください。

    (追加)INDEX(campaign_id, node_id, domain, log_time)は、 '新しい'クエリに必要です。

    どちらの場合も、log_timeが最後になります。他の列は任意の順序にすることができます。注文を並べ替えると、他のクエリに役立つ場合があります。両方のクエリに最適なインデックスはありません。

    次に、USE INDEXを使用しないでください。それは逆行するかもしれない。

    More cookbook tips

    より良い解決策はより複雑です:頻繁に必要とされるさまざまなカウンター/合計のサマリーテーブルを構築し、維持します。 (おそらく、30分の時間範囲を使用します)警告:COUNT(DISTINCT ...)はサマリーテーブルでは処理できません。

    なぜこれらのIDはVARCHAR(50)で、INT UNSIGNEDではないのですか?また、domainなどの他のフィールドを正規化することで利益を得ることができます。 log_typeは、1バイトのENUMとすることができます。

    本当にすべての列をNULL可能にする必要がありますか?

    これらの列の組み合わせは一意ですか? InnoDBは実際にPRIMARY KEYが好きです。

    +0

    ご返信ありがとうございます。私はあなたの提案されたインデックスで試してみましたが、結果を得るために時間がかかり、node_idカラムのインデックスに返信しませんでした。あなたはそれに返答することができます。 – Rams

    +0

    元のクエリには1つのインデックスが必要です。 node_idを使用した新しいクエリーには別のクエリーが必要です。 (私は私の答えにいくつかの段落を追加しました) –

    +0

    これらのクエリを実行するには、いくつの行がタッチされますか?それが何百万というのであれば、おそらくサマリーテーブルについて話すべきです。 –

    関連する問題