1

かなり大きなデータセットに対して単純なクエリと思われるものを実行しようとしていますが、実行に非常に時間がかかります。「データを送信中」状態で 3 ~ 4 時間以上停止します。

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

CREATE TABLE `transaction` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`uuid` varchar(36) NOT NULL,
`userId` varchar(64) NOT NULL,
`protocol` int(11) NOT NULL,
... A few other fields: ints and small varchars
`created` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `uuid` (`uuid`),
KEY `userId` (`userId`),
KEY `protocol` (`protocol`),
KEY `created` (`created`)
) ENGINE=InnoDB AUTO_INCREMENT=61 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4 COMMENT='Transaction audit table'

クエリは次のとおりです。

select protocol, count(distinct userId) as count from transaction
where created > '2012-01-15 23:59:59' and created <= '2012-02-14 23:59:59'
group by protocol;

テーブルには約 2 億 2,200 万行あり、クエリの where 句は約 2,000 万行に絞り込みます。個別のオプションを使用すると、約 700,000 の個別の行に削減され、グループ化後 (およびクエリが最終的に終了したとき)、実際には 4 ~ 5 行が返されます。

大量のデータであることは認識していますが、このクエリの場合、4 ~ 5 時間は非常に長いようです。

ありがとう。

編集: 参考までに、これは db.m2.4xlarge RDS データベース インスタンスの AWS で実行されています。

4

3 に答える 3

11

クエリをプロファイリングして、何が起こっているのかを正確に確認してみませんか?

SET PROFILING = 1; 
SET profiling_history_size = 0; 
SET profiling_history_size = 15; 
/* Your query should be here */
SHOW PROFILES; 
SELECT state, ROUND(SUM(duration),5) AS `duration (summed) in sec` FROM information_schema.profiling WHERE query_id = 3 GROUP BY state ORDER BY `duration (summed) in sec` DESC; 
SET PROFILING = 0; 
EXPLAIN /* Your query again should appear here */;

これは、クエリに時間がかかる正確な場所を確認し、結果に基づいて最適化操作を実行できるようにするのに役立つと思います。

于 2012-04-11T05:15:54.163 に答える
3

これは非常に重いクエリです。なぜそんなに時間がかかるのかを理解するには、詳細を理解する必要があります。

インデックス付きフィールドに範囲条件があります。つまり、MySQL はインデックスで作成された最小の値を見つけ、値ごとにインデックスから対応する主キーを取得し、ディスクから行を取得し、必要なフィールド (protocol、userId) をフェッチします。 ) 現在のインデックス レコードにない場合、それらを「一時テーブル」に配置し、それらの 700000 行をグループ化します。インデックスは実際に使用でき、ここでは範囲条件を高速化するためだけに使用されます。

それを高速化する唯一の方法は、必要なすべてのデータを含むインデックスを作成することです。これにより、MySQL は行のディスク ルックアップを行う必要がなくなります。それは と呼ばれcovering indexます。ただし、インデックスはメモリ内に存在し、〜sizeOf(created+protocol+userId+PK)*rowCountバイトを含むことを理解する必要があります。これは、テーブルを更新するクエリや他のインデックスにとって負担になる可能性があります。別の集計テーブルを作成し、クエリを使用してテーブルを定期的に更新する方が簡単です。

于 2012-04-11T08:12:46.573 に答える
1

distinct と group by の両方で、一時データをサーバーに並べ替えて保存する必要があります。これほど多くのデータがあると、時間がかかる場合があります。

userId、created、および protocol のさまざまな組み合わせにインデックスを付けると役立ちますが、どれだけ、またはどのインデックスが最も役立つかはわかりません。

于 2012-04-11T04:10:26.703 に答える