4

次のような MySQL テーブルがあります (意味のない列は削除されています)。

CREATE TABLE `my_data` (
  `auto_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `created_ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_ts` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `data_txt` varchar(256) CHARACTER SET utf8 NOT NULL,
  `issued_ts` timestamp NULL DEFAULT NULL,
  `account_id` int(11) NOT NULL,
  PRIMARY KEY (`auto_id`),
  KEY `account_issued_idx` (`account_id`,`issued_ts`),
  KEY `account_issued_created_idx` (`account_id`,`issued_ts`,`created_ts`),
  KEY `account_created_idx` (`account_id`,`created_ts`),
  KEY `issued_idx` (`issued_ts`)
) ENGINE=InnoDB;

テーブルには約 9 億行あり、1 つの account_id がそれらの行の 65% 以上を占めています。account_idに依存するcreated_tsとissued_tsの両方の日付範囲にわたるクエリを作成するように求められています.account_idは、自動インクリメントキーに1:1の機能依存関係があるようです.

典型的なクエリは次のようになります。

SELECT * 
FROM my_data 
WHERE account_id = 1 AND 
      created_ts > TIMESTAMP('2012-01-01') AND 
      created_ts <= TIMESTAMP('2012-01-21') 
ORDER BY created_ts DESC LIMIT 100;

クエリの EXPLAIN は、これを示しています。

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: my_data
         type: range
possible_keys: account_issued_idx, account_issued_created_idx, account_created_idx,
      key: account_issued_created_idx
  key_len: 8
      ref: NULL
     rows: 365314721
    Extra: Using where

問題は、クエリに時間がかかりすぎて、最終的に強制終了されることです。OS(Linux)がスワップスペースを使い果たしたため、データベースホストがダウンしました。

私はこの問題を繰り返し調査し、クエリを相関関係のないサブクエリに分割し、インデックスを強制し、明示的な SELECT 句を使用し、日付範囲のウィンドウを制限しようとしましたが、結果は同じです: パフォーマンスの低下 (あまりにも遅い)、ホストに負担がかかりすぎます(常に死にます)。

私の質問は次のとおりです。

  1. データを日付範囲にスライスし、リアルタイム呼び出しで許容できるように実行するようにクエリを作成することは可能ですか? ( < 1 秒)

  2. 要求されているパフォーマンスを得るために、欠けている、または役立つ可能性のある最適化はありますか?

その他の提案、ヒント、または考えは大歓迎です。

ありがとう

4

5 に答える 5

4

mysql がこのクエリに間違ったインデックスを使用しているようです。別のインデックスを強制してみてください:

SELECT * 
FROM my_data FORCE INDEX (`account_created_idx`)
WHERE account_id = 1 AND 
      created_ts > TIMESTAMP('2012-01-01') AND 
      created_ts <= TIMESTAMP('2012-01-21') 
ORDER BY created_ts DESC LIMIT 100;
于 2012-05-24T16:41:10.627 に答える
1

この質問は何年も続いています。それでも、良い答えがあります。

あなたの闘争の鍵は、取るに足らない列が削除されたあなたの言葉にあります。 あなたがするとき、重要でない列はありませんSELECT * .... ORDER BY X DESC LIMIT N。これは、結果セット全体を取得してシャッフルする必要があるためです。複雑なテーブルのすべての列を要求すると、大量のデータになります。

WHERE句の適切なインデックスがあります。ORDER BYそれがその中で言われていなければ、それは条項にとっても良いでしょうDESC.

あなたが望むのは遅延結合です。必要な行の ID だけを取得することから始めます。

        SELECT auto_id
          FROM my_data
         WHERE account_id = 1 AND 
              created_ts > TIMESTAMP('2012-01-01') AND 
              created_ts <= TIMESTAMP('2012-01-21') 
     ORDER BY created_ts DESC
        LIMIT 100

auto_idこれにより、必要な列の値のリストが得られます。このリストを並べ替えるために、MySql は id とタイムスタンプの値をシャッフルするだけです。処理するデータが大幅に少なくなります。

次に、JOINその ID のリストをメイン テーブルに追加し、結果を取得します。

SELECT a.*
  FROM my_data a
  JOIN (
             SELECT auto_id
               FROM my_data
              WHERE account_id = 1 AND 
                    created_ts > TIMESTAMP('2012-01-01') AND 
                    created_ts <= TIMESTAMP('2012-01-21') 
           ORDER BY created_ts DESC
              LIMIT 100
       ) b ON a.auto_id = b.auto_id
 ORDER BY a.created_ts DESC

これを試して。おそらく多くの時間を節約できます。

auto_id と created_ts の両方が単調に増加することが先験的にわかっている場合は、さらにうまくいく可能性があります。サブクエリには次を含めることができます

      ORDER BY auto_id DESC
         LIMIT 100

これにより、さらにシャッフルする必要のあるデータが削減されます。

SELECT *プロのヒント:本番システムでは避けてください。代わりに、実際に必要な列を列挙してください。これには多くの理由があります。

于 2015-04-15T00:28:44.440 に答える
0

比較では関数を使用しないでください。タイムスタンプを計算し、計算された値を使用します。そうしないと、インデックスを使用してcreated_tsを比較できず、結果セットから数百万行をフィルタリングするフィールドになります。

于 2012-05-24T17:24:43.420 に答える
0

MySQL が (明らかに) 最適ではないインデックスを使用する理由がわかりません。インデックスを強制する以外に、EXPLAINこのバリエーションで計画を試すことができますか:

SELECT * 
FROM my_data 
WHERE account_id = 1 AND 
      created_ts > TIMESTAMP('2012-01-01') AND 
      created_ts <= TIMESTAMP('2012-01-21') 
ORDER BY account_id
       , created_ts DESC 
LIMIT 100;
于 2012-05-24T17:30:13.517 に答える
0

MariaDB (または MySQL 5.6) を試してください。オプティマイザーの方が高速です。数か月使用していますが、あなたのようなクエリでは 1000% 高速です。

Index Condition Pushdown が必要です: http://kb.askmonty.org/en/index-condition-pushdown/

于 2012-05-24T17:14:17.667 に答える