2

次の表を検討してください。

tweets                        daterange
---------------------------   ----------------
tweet_id  nyse_date   class   _date
---------------------------   ----------------
 1        2011-03-12  2       2011-03-11
 2        2011-03-12  1       2011-03-12
 3        2011-03-12  1       2011-03-13
 4        2011-03-12  1       2011-03-14
 5        2011-03-12  0       2011-03-15
 7        2011-03-13  1
 8        2011-03-13  2
 9        2011-03-13  3
10        2011-03-14  3

各ツイートには、1、2、または3のいずれかの「クラス」が割り当てられています。データ範囲内の各クラスの各クラスのツイート数の概要が必要です。2011-03-11したがって、とに関するツイートはありませんが2011-03-15、次のように、その日付を結果セットに含める必要があります。

nyse_date   total  class1  class2  class3
-----------------------------------------
2011-03-11  0      0       0       0
2011-03-12  5      3       1       0
2011-03-13  3      1       1       1     
2011-03-14  1      0       0       1
2011-03-15  0      0       0       0

次のクエリを試しましたが、タイムアウトになります(データベースがそれほど大きくないため、タイムアウトするはずがありません)。

SELECT
  t.nyse_date,
  COUNT(CASE WHEN t.nyse_date = d._date THEN 1 END) total, 
  SUM(t.class=1) as neu,
  SUM(t.class=2) as pos,
  SUM(t.class=3) as neg
FROM tweets t
CROSS JOIN
  daterange d
GROUP BY t.nyse_date
ORDER BY t.nyse_date ASC

これがEXPLAIN

id select_type table type possible_keys key  key_len ref    rows    Extra
---------------------------------------------------------------------------------------------------
1  SIMPLE      d     ALL  NULL          NULL NULL    NULL   148     Using temporary; Using filesort
1  SIMPLE      t     ALL  NULL          NULL NULL    NULL   560783  Using join buffer

私は何が間違っているのですか?日付範囲テーブルのすべての日付が含まれていることを確認するためのより効率的な方法はありますか?

edit:私もこのクエリを試しましたが、結果は同じままです-タイムアウトするまで実行されます。

SELECT 
  t.nyse_date,
  COUNT(t.tweet_id) AS total, 
  SUM(t.class=1) AS neu,
  SUM(t.class=2) AS pos,
  SUM(t.class=3) AS neg
FROM tweets t
LEFT JOIN
  daterange d
  ON t.nyse_date = d._date
GROUP BY t.nyse_date
ORDER BY t.nyse_date ASC

これがEXPLAIN

id select_type table type possible_keys key  key_len ref  rows    Extra
-------------------------------------------------------------------------------------------------
1  SIMPLE      t     ALL  NULL          NULL NULL    NULL 560783  Using temporary; Using filesort
1  SIMPLE      d     ALL  NULL          NULL NULL    NULL 148
4

2 に答える 2

3

クエリの実行が遅い理由は、tweetsテーブルのインデックスを使用していないためです。

(sp100_id, nyse_date)これから行うことは、テーブルの列に複合インデックスを作成してから、次のtweetsクエリを実行することです。

SELECT     
    a.sp100_id,
    b._date,
    COALESCE(c.total,0) AS total,
    COALESCE(c.neu,0) AS neu,
    COALESCE(c.pos,0) AS pos,
    COALESCE(c.neg,0) AS neg,
    COALESCE(c.spamneu,0) AS spamneu
FROM
    sp100 a
CROSS JOIN 
    daterange b
LEFT JOIN
(
    SELECT 
        sp100_id,
        nyse_date, 
        COUNT(1) AS total,
        COUNT(CASE class WHEN 1 THEN 1 END) AS neu,
        COUNT(CASE class WHEN 2 THEN 1 END) AS pos,
        COUNT(CASE class WHEN 3 THEN 1 END) AS neg,
        COUNT(CASE WHEN class = 1 AND type = 1 THEN 1 END) AS spamneu
    FROM tweets 
    GROUP BY sp100_id, nyse_date
) c ON 
    a.sp100_id = c.sp100_id AND b._date = c.nyse_date
ORDER BY 
    a.sp100_id, b._date

SQLFiddle デモ

于 2012-07-14T16:56:56.720 に答える
1

近かったと思います。しかし、おそらく左側に日付が必要です。

SELECT 
    d.nyse_date,
    COUNT(t.tweet_id) AS total, 
    SUM(t.class=1) AS neu,
    SUM(t.class=2) AS pos,
    SUM(t.class=3) AS neg
FROM daterange d LEFT OUTER JOIN tweets t t.nyse_date = d._date
GROUP BY d.nyse_date
ORDER BY d.nyse_date ASC

インデックスについて結論を急ぐ必要はありません。想定しすぎる前に、正しい方法でクエリを試してください。

編集

私が最初にこれを書いたとき、あなたのテーブルがデータ列に異なる名前を使用していることに気づきませんでした. 無効な列を使用してクエリを作成しました -- d.nyse_date がありません。それを t.nyse_date に変更した場合、または正しい列参照 d._date に変更する代わりに修飾エイリアスを単に削除した場合、15 番目が含まれているデータが返されないという問題を説明できると思います。内部テーブルの値でグループ化されます。

これは動作するはずのバージョンです:

SELECT 
    d._date,
    COUNT(t.tweet_id) AS total, 
    SUM(t.class=1) AS neu,
    SUM(t.class=2) AS pos,
    SUM(t.class=3) AS neg
FROM daterange d LEFT OUTER JOIN tweets t t.nyse_date = d._date
GROUP BY d._date
ORDER BY d._date ASC
于 2012-07-14T16:55:23.787 に答える