2012-02-24 22 views
4

Webアプリケーションのデバッグ情報を格納する大きなテーブルがあります。問題は、テーブルが現在50万行になり、インデックスが使用されていないためクエリの1つが遅いことです。GROUP BY YEAR&MonthのMySQL filesort

SQL:

EXPLAIN SELECT count(*) AS `count`, month(event_date) AS `month`, year(event_date) AS `year`FROM events WHERE 1 = 1 GROUP BY year(event_date) DESC, month(event_date) DESC LIMIT 6; 

結果:

SIMPLE events index NULL event_date 8 NULL 139358 Using index; Using temporary; Using file sort 

そして、ここでは、テーブル構造です。

CREATE TABLE IF NOT EXISTS `events` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Event Primary Key', 
`event_number` int(11) NOT NULL, 
`user_id` int(11) unsigned NOT NULL COMMENT 'User ID', 
`server_id` int(11) unsigned DEFAULT NULL COMMENT 'The ID of the remote log client', 
`remote_id` int(11) unsigned DEFAULT NULL COMMENT 'The Event Primary Key from the remote client', 
`event_date` datetime NOT NULL COMMENT 'Event Datetime in local timezone', 
`event_date_utc` datetime NOT NULL COMMENT 'Event Datetime in UTC timezone', 
`event_type` varchar(255) NOT NULL COMMENT 'The type of event', 
`event_source` varchar(255) NOT NULL COMMENT 'Text description of the source of the event', 
`event_severity` varchar(255) NOT NULL COMMENT 'Notice, Warning etc', 
`event_file` text NOT NULL COMMENT 'The full file location of the source of the event', 
`event_file_line` int(11) NOT NULL COMMENT 'The line in the file that triggered the event', 
`event_ip_address` varchar(255) NOT NULL COMMENT 'IP Address of the user that triggered the event', 
`event_summary` varchar(255) NOT NULL COMMENT 'A summary of the description', 
`event_description` text NOT NULL COMMENT 'Full description of the event', 
`event_trace` text NOT NULL COMMENT 'Full PHP trace', 
`event_synced` int(1) unsigned DEFAULT '0', 
PRIMARY KEY (`id`), 
KEY `event_type` (`event_type`), 
KEY `event_source` (`event_source`), 
KEY `user_id` (`user_id`), 
KEY `server_id` (`server_id`), 
KEY `event_date` (`event_date`) 
) 

誰かが素晴らしいファイルの並べ替えなしで同じ結果を得るためのアイデアを持っている場合!

答えて

1

重要な問題は、WHERE句を指定していないことです。 WHERE 1=1の使用は無意味です。問題は、行数を制限せずにYEARMONTHをMySQLから取得しようとしているため、GROUPを処理できるようになる前に各行に対してMONTH(..)とYEAR(...)を処理することです。

私の以前の提案の後にINDEXを使用していないという事実は、あなたが照会するよりも多くのクエリを持っていることを示しています。その場合は私に知らせてください。そうでなければ、私は以下をチェックすることをお勧めします(あなたが達成しようとしていることを明記していないので、推測する必要はありますが)。大きな助けとなる。あなたがが、追加の基準を持っている場合はその場合は更新してくださいので

SELECT 
    COUNT(id) AS `count`, 
    MONTH(event_date) AS `month`, 
    YEAR(event_date) AS `year` 
FROM events 
-- Get the first day of this month, and subtract 6 months 
WHERE event_date > SUBDATE(DATE_FORMAT(NOW(), '%Y-%m-01'), INTERVAL 6 MONTH) 
GROUP BY `year` DESC, `month` DESC; 

が、それは与えられたアドバイスを変更します

+0

こんにちは、サイモン、返信ありがとうございます。残念ながら、これはスピードを全く改善していないようです。 'year' DESC BY = 1 GROUP、' month' DESCイベントからyear' '' AS count'、month' 'AS MONTH(EVENT_DATE)、YEAR(EVENT_DATE)として選択した数(ID)を説明 LIMIT 6 結果:一時的な使用。ファイルソートの使用。 –

+0

まず、WHERE 1 = 1は必要ありません。第2に私は答えを改訂しますが、重要な問題は行の数を制限するWHEREの不足であるため、データベース全体を照会して並べ替え、グループ化して上位6行を取得する必要があります。 WHERE構文を使用している場合(WHERE 1 = 1を続けて使用する場合)、投稿してください。これにより、適切なアドバイスがはるかに容易になります。 –

+0

こんにちはSimon、 はい、event_typeとevent_sourceにいくつかのフィルタリング(WHERE)があります。 提案したようにSUBDATEを使用して返された行を制限することが役に立ちました。 ORDER BY NULLは実際にはあまり役に立たないようですが、私はそれを考えましたが、大きなデータベースで試しても問題は残っています。 基本的には、インデックスだけではこのクエリを実行できないということですか?テーブルのサイズは約300mbyteです。パフォーマンスを向上させるために、私は本当にMySQLのキーバッファのキャッシュサイズを増やす必要があります。 クエリがかなりシンプルなのでちょっと変わっているようです。 –

4

GROUP BYは、MySQL

だからNULL、ORDER BYを追加してみてください、ORDER BYを意味します:これは、通常、他の人がPOSを持っているものに加えて、MySQLのドキュメントに

+0

ありがとうございます。 ORDER BY NULLは、ファイルの並べ替えを削除するように見えるので、大きな改善です。 –

+0

ちょうどアップデート。これはまだ一時テーブルに結果を生成させていると思われます。つまり、キーキャッシュは返される結果と同じくらい大きくする必要があります。 これに加えて、event_date> SUBDATE(DATE_FORMAT(NOW()、 '%Y-%m-01')、INTERVAL 6 MONTH)は大いに役立ちますが、まだ高速ですが、現在のハードウェア設定。 もう一度お世話になりました。 –

0

をfilesortレコード

参照"ORDER BY Optimization"を排除しますted:

EXPLAIN SELECT...を実行し、そのクエリにインデックスを使用しない(または目的のインデックスを使用しない)と報告した場合は、SELECT... FORCE INDEX...でデータをクエリして解決できます。この構文の詳細については、こちらを見て:http://dev.mysql.com/doc/refman/5.6/en/index-hints.html

0
  1. あなたがテーブル全体がスキャンされるように、すべての行を選択することを意味する* SELECTを使用している - もあり

  2. を表示するために特定の行を選択してみてくださいデータをフィルタリングするパラメータがないため、テーブル全体が読み込まれ、返されます。日付または他のパラメータで制限を試してください。