1

テーブル構造:

CREATE TABLE `mytable` (
  `id` varchar(8) NOT NULL,
  `event` varchar(32) NOT NULL,
  `event_date` date NOT NULL,
  `event_time` time NOT NULL,
  KEY `id` (`id`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8

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

 id      | event      | event_date  | event_time
---------+------------+-------------+-------------
ref1     | someevent1 | 2010-01-01  | 01:23:45
ref1     | someevent2 | 2010-01-01  | 02:34:54
ref1     | someevent3 | 2010-01-18  | 01:23:45
ref2     | someevent4 | 2012-10-05  | 22:23:21
ref2     | someevent5 | 2012-11-21  | 11:22:33

テーブルには、これに類似した約500.000.000レコードが含まれています。

ここで質問したいクエリは次のようになります。

SELECT     *
FROM       `mytable`
WHERE      `id` = 'ref1'
ORDER BY   event_date DESC,
           event_time DESC
LIMIT      0, 500

EXPLAIN出力は次のようになります。

select_type:   SIMPLE
table:         E
type:          ref
possible_keys: id
key:           id
key_len:       27
ref:           const     
rows:          17024 (a common example)
Extra:         Using where; Using filesort

目的:このクエリはWebサイトによって生成され、LIMIT-valuesはページナビゲーション要素用であるため、ユーザーが古いエントリを表示したい場合は、に調整さ500, 5001000, 500ます。

フィールド内の一部の項目はid非常に多くの行に設定できるため、行が増えると、もちろんクエリが遅くなります。これらの遅いクエリをプロファイリングすると、その理由は並べ替えであることがわかりました。ほとんどの場合、クエリ中はmysqlサーバーがデータの並べ替えでビジー状態になっています。フィールドにインデックスを付けても、それほど変更はありませんでしたevent_dateevent_time

結果の例SHOW PROFILE、期間でソート:

state          | duration/sec | percentage
---------------|--------------|-----------
Sorting result |     12.00145 |   99.80640
Sending data   |      0.01978 |    0.16449
statistics     |      0.00289 |    0.02403
freeing items  |      0.00028 |    0.00233
...
Total          |     12.02473 |  100.00000

今の質問:

他のサーバー構成オプションなどのmysql変数を深く掘り下げる前にsort_buffer_size、クエリまたは並べ替えの動作を変更する方法を考えてみてください。そうすれば、並べ替えはパフォーマンスを大幅に低下させることはなく、このクエリの目的は引き続き有効です。

私は少し独創的な考えを気にしません。

前もって感謝します!

4

3 に答える 3

2

コメントで書いたように、複数列のインデックス (id、evet_date desc、event_time desc) が役立つ場合があります。

このテーブルが急速に拡大する場合は、ユーザーが特定の日付範囲のデータを選択できるように、アプリケーションにオプションを追加することを検討する必要があります。

例: 最初のステップでは常に 500 レコードが返されますが、次のレコードを選択するには、データの日付範囲を設定してからページネーションを設定する必要があります。

于 2012-11-09T13:37:40.450 に答える
1

インデックス作成が解決策である可能性が最も高いです。あなたはそれを正しくしなければなりません。これについては、mysqlリファレンスページを参照してください。

これを行う最も効果的な方法は、に3つの部分からなるインデックスを作成することです(id, event_date, event_time)。インデックスで指定できますevent_date desc, event_time descが、必要ないと思います。

于 2012-11-09T13:32:43.243 に答える
1

私は、sufleRが提案することから始めます-(id、event_date desc、event_time desc)の複数列インデックス。

ただし、http://dev.mysql.com/doc/refman/5.0/en/create-index.htmlによると、DESC キーワードはサポートされていますが、実際には何もしません。これは少し面倒です。試してみて、パフォーマンスが向上するかどうかを確認してください。ただし、おそらく改善されません。

その場合は、自動的に減分する値を持つ「sort_column」を作成してごまかす必要があるかもしれません (アプリケーション層でこれを行う必要があることは間違いありません。MySQL では減分できないと思います)。その列をインデックスに追加します。

最終的には次のようになります。

id      | event      | event_date  | event_time  | sort_value
---------+------------+-------------+-------------------------
ref1     | someevent1 | 2010-01-01  | 01:23:45   | 0
ref1     | someevent2 | 2010-01-01  | 02:34:54   | -1
ref1     | someevent3 | 2010-01-18  | 01:23:45   | -2
ref2     | someevent4 | 2012-10-05  | 22:23:21   | -3
ref2     | someevent5 | 2012-11-21  | 11:22:33   | -4

および ID と sort_value のインデックス。

汚いですが、他の唯一の提案は、他の方法で where 句に一致するレコードの数を減らすことです。たとえば、インターフェイスを変更して、500 レコードではなく、特定の日付のレコードを返すようにします。

于 2012-11-09T13:34:09.877 に答える