2

次の簡単なMySQLクエリがあります。

SELECT SQL_NO_CACHE mainID
FROM tableName 
WHERE otherID3=19
AND dateStartCol >= '2012-08-01' 
AND dateStartCol <= '2012-08-31';

これを実行すると、36074の結果が返されるまで0.29秒かかります。より多くの結果(65703)を返すために日付期間を増やすと、0.56で実行されます。同じサーバーで異なるテーブル(一部のテーブルは大きい)で他の同様のSQLクエリを実行すると、結果は約0.01秒で返されます。

0.29は遅くはありませんが、これは複雑なクエリの基本的な部分であり、このタイミングはスケーラブルではないことを意味します。

テーブルの定義とインデックスについては、以下を参照してください。

使用量が非常に少ない開発サーバーでも同じ問題が発生するため、サーバーの負荷ではないことはわかっています。

+---------------------------+--------------+------+-----+---------+----------------+
| Field                     | Type         | Null | Key | Default | Extra          |
+---------------------------+--------------+------+-----+---------+----------------+
| mainID                    | int(11)      | NO   | PRI | NULL    | auto_increment |
| otherID1                  | int(11)      | NO   | MUL | NULL    |                |
| otherID2                  | int(11)      | NO   | MUL | NULL    |                |
| otherID3                  | int(11)      | NO   | MUL | NULL    |                |
| keyword                   | varchar(200) | NO   | MUL | NULL    |                |
| dateStartCol              | date         | NO   | MUL | NULL    |                |
| timeStartCol              | time         | NO   | MUL | NULL    |                |
| dateEndCol                | date         | NO   | MUL | NULL    |                |
| timeEndCol                | time         | NO   | MUL | NULL    |                |
| statusCode                | int(1)       | NO   | MUL | NULL    |                |
| uRL                       | text         | NO   |     | NULL    |                |
| hostname                  | varchar(200) | YES  | MUL | NULL    |                |
| IPAddress                 | varchar(25)  | YES  |     | NULL    |                |
| cookieVal                 | varchar(100) | NO   |     | NULL    |                |
| keywordVal                | varchar(60)  | NO   |     | NULL    |                |
| dateTimeCol               | datetime     | NO   | MUL | NULL    |                |
+---------------------------+--------------+------+-----+---------+----------------+


+--------------------+------------+-------------------------------+--------------+---------------------------+-----------+-------------+----------+--------+------+------------+---------+
| Table              | Non_unique | Key_name                      | Seq_in_index | Column_name               | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+--------------------+------------+-------------------------------+--------------+---------------------------+-----------+-------------+----------+--------+------+------------+---------+
| tableName          |          0 | PRIMARY                       |            1 | mainID                    | A         |      661990 |     NULL | NULL   |      | BTREE      |         |
| tableName          |          1 | idx_otherID1                  |            1 | otherID1                   | A         |      330995 |     NULL | NULL   |      | BTREE      |         |
| tableName          |          1 | idx_otherID2                  |            1 | otherID2                   | A         |          25 |     NULL | NULL   |      | BTREE      |         |
| tableName          |          1 | idx_otherID3                  |            1 | otherID3                   | A         |          48 |     NULL | NULL   |      | BTREE      |         |
| tableName          |          1 | idx_dateStartCol              |            1 | dateStartCol               | A         |         187 |     NULL | NULL   |      | BTREE      |         |
| tableName          |          1 | idx_timeStartCol              |            1 | timeStartCol               | A         |       73554 |     NULL | NULL   |      | BTREE      |         |
|tableName          |          1 | idx_dateEndCol                 |            1 | dateEndCol                 | A         |         188 |     NULL | NULL   |      | BTREE      |         |
|tableName          |          1 | idx_timeEndCol                 |            1 | timeEndCol                 | A         |       73554 |     NULL | NULL   |      | BTREE      |         |
| tableName          |          1 | idx_keyword                   |            1 | keyword                    | A         |       82748 |     NULL | NULL   |      | BTREE      |         |
| tableName           |          1 | idx_hostname                 |            1 | hostname                   | A         |        2955 |     NULL | NULL   | YES  | BTREE      |         |
| tableName           |          1 | idx_dateTimeCol              |            1 | dateTimeCol                | A         |      220663 |     NULL | NULL   |      | BTREE      |         |
| tableName           |          1 | idx_statusCode               |            1 | statusCode                 | A         |           2 |     NULL | NULL   |      | BTREE      |         |
+--------------------+------------+-------------------------------+--------------+---------------------------+-----------+-------------+----------+--------+------+------------+---------+

出力の説明:

+----+-------------+-----------+-------+----------------------------------+-------------------+---------+------+-------+----------+-------------+
| id | select_type | table     | type  | possible_keys                    | key               | key_len | ref  | rows  | filtered | Extra       |
+----+-------------+-----------+-------+----------------------------------+-------------------+---------+------+-------+----------+-------------+
|  1 | SIMPLE      | tableName | range | idx_otherID3,idx_dateStartCol | idx_dateStartCol | 3       | NULL | 66875 |    75.00 | Using where |
+----+-------------+-----------+-------+----------------------------------+-------------------+---------+------+-------+----------+-------------+
4

3 に答える 3

1

それが本当にあなたのクエリである場合(そして同じものの単純化されたバージョンではない場合)、これは最良の結果を達成するはずです:

 CREATE INDEX table_ndx on tableName( otherID3, dateStartCol, mainID);

最初のインデックスエントリは、の最初の一致WHEREが非常に速いことを意味します。同じことが。にも当てはまりますdateStartCol。3番目のフィールドは非常に小さく、インデックスの速度を大幅に低下させることはありませんが、テーブルにアクセスすることなく、インデックスですぐに必要なデータを見つけることができます。

キーが同じインデックスにあることが重要です。あなたが投稿したEXPLAINものでは、各キーは独自のインデックスに含まれているため、MySQLが最適なインデックスを選択したとしても、パフォーマンスは最適ではありません。コストもかかるため、使用するインデックスの数を減らしてみます(恥知らずなプラグイン:インデックスは実際にSELECTのパフォーマンスを低下させる可能性がありますか?)。

于 2012-10-16T11:07:39.993 に答える
0

これが繰り返し発生するクエリまたは重要なクエリである場合は、複数列のインデックスを作成します。

CREATE INDEX index_name ON tableName (otherID3, dateStartCol)

未使用のインデックスはテーブルの変更にかかる費用がかかるため、削除してください。

ところで、日付と時刻に2つの別々の列は必要ありません。datetime次に、またはtimestampタイプで組み合わせることができます。列が1つ少なく、インデックスが1つ少なくなります。

explain出力は、インデックスを選択したことを示しているのでdateStartCol、上記で提案したのとは逆のことを試すことができます。

CREATE INDEX index_name ON tableName (dateStartCol, otherID3)

クエリのdateStartCol条件でも行の75%が取得されるため、その単一のインデックスを使用してもそれほど改善されないことに注意してください。

どれくらいユニークotherID3ですか?繰り返される回数が少ない場合は、エンジンにそれを使用するようにヒントotherID3を与えることができます。

于 2012-10-16T10:51:48.450 に答える
0

まず、正しいキーを追加してみてください。dateStartColはotherID3よりも選択的であるようです

ALTER TABLE tableName ADD KEY idx_dates(dateStartCol, dateStartCol)

2番目-SELECTにLIMIT句を追加して、必要な行のみを選択するようにしてください。これにより、クエリがアップするはずです。このようにしてみてください:

SELECT SQL_NO_CACHE mainID FROM tableName WHERE otherID3 = 19 AND dateStartCol> = '2012-08-01' AND dateStartCol <= '2012-08-31' LIMIT 10;

また、MySQLが適切に調整されていることを確認してください。http://astellar.com/2011/12/why-is-stock-mysql-slow/で説明されているように、key_buffer_sizeとinnodb_buffer_pool_sizeを確認することをお勧めします。

于 2012-10-16T11:01:16.177 に答える