2


0

多数の行でgroup byを使用しているクエリを最適化する方法

テーブルは次のようになります。

    CREATE TABLE `tweet_tweet` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `text` varchar(256) NOT NULL,
      `created_at` datetime NOT NULL,
      `created_date` date NOT NULL,
...
      `positive_sentiment` decimal(5,2) DEFAULT NULL,
      `negative_sentiment` decimal(5,2) DEFAULT NULL,
      `entity_id` int(11) DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `tweet_tweet_entity_created` (`entity_id`,`created_at`)
    ) ENGINE=MyISAM AUTO_INCREMENT=1097134 DEFAULT CHARSET=utf8

クエリの説明は次のようになります。

mysql> explain SELECT `tweet_tweet`.`entity_id`,
       STDDEV_POP(`tweet_tweet`.`positive_sentiment`) AS `sentiment_stddev`,
       AVG(`tweet_tweet`.`positive_sentiment`) AS `sentiment_avg`,
       COUNT(`tweet_tweet`.`id`) AS `tweet_count`
       FROM `tweet_tweet`
       WHERE `tweet_tweet`.`created_at` > '2010-10-06 16:24:43'
       GROUP BY `tweet_tweet`.`entity_id` ORDER BY `tweet_tweet`.`entity_id` ASC;

+----+-------------+-------------+------+---------------+------+---------+------+---------+----------------------------------------------+
| id | select_type | table       | type | possible_keys | key  | key_len | ref  | rows    | Extra                                        |
+----+-------------+-------------+------+---------------+------+---------+------+---------+----------------------------------------------+
|  1 | SIMPLE      | tweet_tweet | ALL  | NULL          | NULL | NULL    | NULL | 1097452 | Using where; Using temporary; Using filesort |
+----+-------------+-------------+------+---------------+------+---------+------+---------+----------------------------------------------+
  1 row in set (0.00 sec)

毎日約30万行がテーブルに追加されます。 クエリは現在約4秒実行されますが、約1秒に短縮したいので、日が経つにつれてクエリが指数関数的に長くかかるのではないかと心配しています。 tweet_tweetの合計行数は現在1Mを少し超えていますが、急速に増加しています。

これを最適化するための考えはありますか? さらにインデックスが必要ですか? MySQLの代わりにCassandraのようなものを使用する必要がありますか? =)

4 Answer


1


インデックス内のフィールドを並べ替えることができます(つまり、 KEY tweet_tweet_entity_created(created_at、entity_id)。 これにより、mysqlはインデックスを使用して、グループ化および順序付けする必要がある実際の行の量を減らすことができます)。


0


インデックスtweet_tweet_entity_createdを使用していません。 クエリを次のように変更します。

explain SELECT `tweet_tweet`.`entity_id`,
       STDDEV_POP(`tweet_tweet`.`positive_sentiment`) AS `sentiment_stddev`,
       AVG(`tweet_tweet`.`positive_sentiment`) AS `sentiment_avg`,
       COUNT(`tweet_tweet`.`id`) AS `tweet_count`
       FROM `tweet_tweet` FORCE INDEX (tweet_tweet_entity_created)
       WHERE `tweet_tweet`.`created_at` > '2010-10-06 16:24:43'
       GROUP BY `tweet_tweet`.`entity_id` ORDER BY `tweet_tweet`.`entity_id` ASC;

インデックスヒントの詳細については、MySQLマニュアルhttp://dev.mysql.com/doc/refman/5.1/en/index-hints.htmlをご覧ください。

MySQLのクエリオプティマイザーが少し助けを必要とする場合があります。


0


MySQLには汚い小さな秘密があります。 複数の列にわたってインデックスを作成すると、最初の列のみが実際に「使用」されます。 一意キーと外部キーを使用するテーブルを作成しましたが、1つ以上の列に個別のインデックスを設定する必要がしばしばありました。

少なくともcreated_atに余分なインデックスを追加することをお勧めします。 集計列にインデックスを追加しても速度が向上するかどうかはわかりません。


0


mysqlバージョン5.1以降の場合、大きなテーブルのパーティションオプションを検討できます。