1

私の MySQL データベースには 3 億 5000 万を超える行があり、さらに増え続けています。サイズは現在32GBです。SSD と大量の RAM を使用していますが、適切なインデックスを使用していることを確認するためのアドバイスを求めたいと考えています。

CREATE TABLE `qcollector` (
  `key` bigint(20) NOT NULL AUTO_INCREMENT,
  `instrument` char(4) DEFAULT NULL,
  `datetime` datetime DEFAULT NULL,
  `last` double DEFAULT NULL,
  `lastsize` int(10) DEFAULT NULL,
  `totvol` int(10) DEFAULT NULL,
  `bid` double DEFAULT NULL,
  `ask` double DEFAULT NULL,
  PRIMARY KEY (`key`),
  KEY `datetime_index` (`datetime`)
) ENGINE=InnoDB;

show index from qcollector;
+------------+------------+----------------+--------------+-------------+-----------+--    -----------+----------+--------+------+------------+---------+---------------+
| Table      | Non_unique | Key_name       | Seq_in_index | Column_name | Collation |     Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| qcollector |          0 | PRIMARY        |            1 | key         | A         |   378866659 |     NULL | NULL   |      | BTREE      |         |               |
| qcollector |          1 | datetime_index |            1 | datetime    | A         |    63144443 |     NULL | NULL   | YES  | BTREE      |         |               |
+------------+------------+----------------+--------------+-------------+-----------+------    -------+----------+--------+------+------------+---------+---------------+
2 rows in set (0.03 sec)

select * from qcollector order by datetime desc limit 1;
+-----------+------------+---------------------+---------+----------+---------+---------+--------+
| key       | instrument | datetime            | last    | lastsize | totvol  | bid     | ask    |
+-----------+------------+---------------------+---------+----------+---------+---------+--------+
| 389054487 | ES         | 2012-06-29 15:14:59 | 1358.25 |        2 | 2484771 | 1358.25 | 1358.5 |
+-----------+------------+---------------------+---------+----------+---------+---------+--------+
1 row in set (0.09 sec)

遅い典型的なクエリ (全テーブル スキャン、このクエリには 3 ~ 4 分かかります):

explain select date(datetime), count(lastsize) from qcollector where instrument = 'ES' and datetime > '2011-01-01' and time(datetime) between '15:16:00' and '15:29:00' group by date(datetime) order by date(datetime) desc;
+------+-------------+------------+------+----------------+------+---------+------+-----------+----------------------------------------------+
| id   | select_type | table      | type | possible_keys  | key  | key_len | ref  | rows      | Extra                                        |
+------+-------------+------------+------+----------------+------+---------+------+-----------+----------------------------------------------+
|    1 | SIMPLE      | qcollector | ALL  | datetime_index | NULL | NULL    | NULL | 378866659 | Using where; Using temporary; Using filesort |
+------+-------------+------------+------+----------------+------+---------+------+-----------+----------------------------------------------+
4

2 に答える 2

1

date列に対してand関数を使用するとtime、インデックスを効率的に使用できません。日付と時刻を別々の列に保存してそれらにインデックスを付けることもできますが、これはより多くのストレージスペースを占有します.

複数列のインデックスを追加することも検討してください。の索引(instrument, datetime)がおそらくここで役立ちます。

于 2012-07-16T23:19:51.417 に答える
1

考慮すべきいくつかのアイデア:

  • カバリング インデックス (つまり、クエリで参照されるすべての列を含むインデックス) が役立つ場合があります。このようなインデックスは、より多くのディスク (SSD?) スペースを必要としますが、MySQL がインデックスにない列の値を検索するためにデータ ページにアクセスする必要がなくなります。

    ON qcollector (datetime,instrument,lastsize) また

    ON qcollector (instrument,datetime,lastsize)

  • lastsizeNULL 値を持つ行をカウントから除外する必要がありますか? 代わりにすべての行の数を返すことができますか? COUNT(1)代わりにorを返すことができればSUM(1)、クエリはlastsize列を参照する必要がないため、インデックスでカバリング インデックスにする必要はありません。

    式はCOUNT(lastsize)次と同等ですSUM(IF(lastsize IS NULL,0,1))

  • lastsize日時範囲に NULL 値しかない場合に日付を返す必要がありますか? または NULL を含むすべての行をlastsize除外できますか? つまり、次のような述語を含めることができますか

    AND lastsize IS NOT NULL

あなたのクエリで?

それらはいくつかを助けるかもしれません。


大きな問題は、TIME(datetime)式の述語が検索可能でないことだと思います。つまり、MySQL はそれらに対してインデックス範囲スキャン操作を使用しません。裸のdatetime列の述語は検索可能です...そのため、EXPLAIN は datetime_index を可能なキーとして表示しています。

もう 1 つの大きな問題は、クエリが派生式GROUP BYORDER BY操作していることです。この場合、MySQL は中間結果セットを (一時的な MyISAM テーブルとして) 生成し、その結果セットを処理する必要があります。また、処理する行が多数ある場合、これは非常に手間のかかる作業になる可能性があります。


テーブルの変更に関しては、DATE 列と TIME 列を別々に使用し、DATETIME の代わりに TIMESTAMP データ型を使用することを検討します (日付と時刻を一緒に格納する必要がある場合)。そのままの DATE 列とそのままの TIME 列を参照するようにクエリを書き直し、リライトされたクエリで参照されるすべての列を含むカバリング インデックスを追加することを検討します。先頭の列はカーディナリティが最も高い列です (そして、クエリ)

于 2012-07-16T23:48:32.110 に答える