0

このクエリは、特定の日付範囲内のユニーク ユーザー セッションをすべて選択します。

select distinct(accessid) from accesslog where date > '2009-09-01'

次のフィールドにインデックスがあります。

  • アクセスした
  • 日にち
  • いくつかの他のフィールド

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

mysql> explain select distinct(accessid) from accesslog where date > '2009-09-01';
+----+-------------+-----------+-------+----------------------+------+---------+------+-------+------------------------------+
| id | select_type | table     | type  | possible_keys        | key  | key_len | ref  | rows  | Extra                        |
+----+-------------+-----------+-------+----------------------+------+---------+------+-------+------------------------------+
|  1 | SIMPLE      | accesslog | range | date,dateurl,dateaff | date | 3       | NULL | 64623 | Using where; Using temporary |
+----+-------------+-----------+-------+----------------------+------+---------+------+-------+------------------------------+


mysql> explain select distinct(accessid) from accesslog;
+----+-------------+-----------+-------+---------------+----------+---------+------+---------+-------------+
| id | select_type | table     | type  | possible_keys | key      | key_len | ref  | rows    | Extra       |
+----+-------------+-----------+-------+---------------+----------+---------+------+---------+-------------+
|  1 | SIMPLE      | accesslog | index | NULL          | accessid | 257     | NULL | 1460253 | Using index |
+----+-------------+-----------+-------+---------------+----------+---------+------+---------+-------------+

date 句を含むクエリで accessid インデックスを使用しないのはなぜですか?

特定の日付範囲で個別の accessid のクエリを高速化するために使用できる他のインデックスはありますか?

編集 - 解決

列幅をaccessidvarchar 255 から char 32 に減らすと、クエリ時間が最大 75% 改善されました。

date+accessidインデックスを追加しても、クエリ時間には影響しませんでした。

4

6 に答える 6

5

のインデックス(date,accessid) 役立ちます。ただし、インデックスを微調整する前に、accessid列のタイプを確認することをお勧めします。EXPLAINは、キーの長さが 257 バイトであることを示しています。これは、ID 列としては長すぎるように思えます。VARCHAR(256)forを使用していaccessidますか? ならば、もっとコンパクトなタイプは使えないの?数字の場合はINT( SMALLINT, BIGINT, 必要に応じて) する必要があり、英数字の ID の場合は、実際に 256 文字の長さにできますか? その長さが固定されている場合、代わりにCHARCHAR(32)たとえば)を使用できませんか?

于 2009-09-11T06:08:07.687 に答える
2

問題は、条件が範囲句 (日付列) であることです。

MySQL は範囲条件の後でインデックス列を使用できないため、date->accessid の複数列インデックスは状況を改善しない可能性があります。理論的には、この場合の計算をカバーするためにそれを使用できるはずですが、MySQL の欠点のようです。この状況で複数列インデックスを正常に使用することはできませんでした。

(date,accessid) にインデックスを作成して、それを使用してクエリをカバーすることを期待できます (したがって、テーブルにアクセスする必要はありません) が、あまり期待できません。あなたができることは大したことではありません。

編集:

私の答えはHigh Performance MySQL - Second Editionの厚意によるものであり、MySQL の本格的な開発を行う必要がある場合は、それだけの価値があります。

于 2009-09-11T06:00:20.760 に答える
0

date 句を含むクエリで accessid インデックスが使用されないのはなぜですか?

日付インデックスを使用する方が効率的だからです。これは、検索スペースをより速く縮小する可能性が高いためです。

アクセスIDはそのインデックスの日付内でソートされるため、少なくとも1つのDBMS(DB2/z、MySQLについてはあまり知りません)は、date + accessidのインデックスから恩恵を受けるでしょう。その DBMS は date+accessid キーを使用して、where 句を効率的に使用して検索スペース絞り込み、そのスペース内で accessid の個別の値を返します。

MySQL がそれほど賢いかどうかはわかりません。私の提案は、それを試してみることです (これは、ほとんどの DB 最適化に関する質問に対する最良の答えです)。

于 2009-09-11T05:53:02.660 に答える
0

where句で使用するものであるため、クエリは「日付」インデックスを使用します。

これが唯一の賢明なオプションです。アクセス ID インデックスを使用する場合は、すべてのアクセス ID 行を読み取り、その前の日付を確認してから、それが異なるかどうかを判断する必要があります。

これが非常に大きなテーブルである場合は、日付とアクセス ID の複合インデックスが役立つ場合があります。

于 2009-09-11T05:56:17.303 に答える
0

テストする方法はありませんが、間違いなくaccessid と date の両方にまたがるインデックスを追加しようとします。

多くの場合、錬金術のようなインデックスの最適化。異なる DBMS は異なる動作をするため、さまざまな組み合わせを試す (そして失敗する) 必要がある場合があります。推論が不可能だと言っているのではありません。それは多くの場合ですが、ある点までです。多くの場合、直感に従った方が速くて簡単です。

于 2009-09-11T05:59:50.073 に答える
0

date 句を含むクエリで accessid インデックスが使用されないのはなぜですか?

日付インデックスを使用すると、テーブル内のデータの大部分を無視できるためです。おそらく、テーブルにはほとんどの履歴データが保持されており、その多くは今月の初めよりもずっと前の日付を参照しているため、日付基準は選択的であり、オプティマイザーがほとんどのデータを無視できるようにすることでワークロードを軽減します。データの。

accessid インデックスを使用した場合、各行 (および各インデックス エントリ) を読み取って、日付が検索条件を満たしているかどうかを確認する必要があります。これは、インデックス全体とテーブル全体を読み取ることを意味します。実際、コンテキストではインデックスを無視する方が適切ですが、「accessid インデックスを使用した場合」から始めました。

特定の日付範囲で個別の accessid のクエリを高速化するために使用できる他のインデックスはありますか?

オプティマイザーの精巧さによっては、(date, accessid) のインデックスが改善される場合があります。インデックスの先頭の列で範囲検索を実行できます。末尾の列は、アクセス ID を確立するためにテーブル内のデータを参照する必要がないことを意味します。情報はインデックス内にあります。したがって、これにより、インデックスとテーブルにアクセスするクエリがインデックスのみにアクセスするクエリに変換される可能性があります。これにより、必要な I/O の量が減り、クエリのパフォーマンスが向上します。

他の列からのデータを必要とする他の条件がある場合、または一意の accessid 値以上のものを返す必要がある場合は、テーブル データの一部を読み取ることになります。これはおそらく、テーブル全体をスキャンするよりも有利です。

于 2009-09-11T06:01:40.160 に答える