4

900 万行を超える非常に大きなテーブルがあり、私のソフトウェアでは、選択クエリをループですばやく実行する必要があります。問題は、クエリが完了するまでに約 4 秒かかることです。以下にクエリの 1 つを示します (クエリの速度を低下させている同じ WHERE 句があるという点で、これらはすべて類似しています。

SELECT MIN(id)
FROM `04c1Tg0M`
WHERE `tried` = 0;

試した列をブール値として使用しています。値は 1 または 0 です。そのクエリの EXPLAIN は次のとおりです。

--------+--------------------------+
| id | select_type | table    | type  | possible_keys | key  | key_len | ref  | rows    | Extra                    |
+----+-------------+----------+-------+---------------+------+---------+------+---------+--------------------------+
|  1 | SIMPLE      | 04c1Tg0M | index | NULL          | pdex | 158     | NULL | 9275107 | Using where; Using index |
+----+-------------+----------+-------+---------------+------+---------+------+---------+--------------------------+

テーブル構造は次のとおりです。

CREATE TABLE `04c1Tg0M` (
    `id` int(20) NOT NULL AUTO_INCREMENT,
    `username` varchar(50) NOT NULL,
    `tried` tinyint(1) DEFAULT '0',
    PRIMARY KEY (`id`),
    KEY `pdex` (`username`,`id`,`tried`)
) ENGINE=MyISAM AUTO_INCREMENT=9275108 DEFAULT CHARSET=utf8

show indes の出力は次のとおりです。

| Table    | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| 04c1Tg0M |          0 | PRIMARY  |            1 | id          | A         |     9275107 |     NULL | NULL   |      | BTREE      |         |
| 04c1Tg0M |          1 | pdex     |            1 | username    | A         |     9275107 |     NULL | NULL   |      | BTREE      |         |
| 04c1Tg0M |          1 | pdex     |            2 | id          | A         |     9275107 |     NULL | NULL   |      | BTREE      |         |
| 04c1Tg0M |          1 | pdex     |            3 | tried       | A         |     9275107 |     NULL | NULL   | YES  | BTREE      |         |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+

問題のクエリからの出力は次のとおりです。

+---------+
| MIN(id) |
+---------+
|       1 |
+---------+
1 row in set (3.76 sec)

クエリ時間を大幅に短縮する必要があります。どんな助けでも大歓迎です。

4

3 に答える 3

6

にインデックスを追加する必要があります(tried, id)

すでにインデックスを追加しましたが、フィールドがインデックスの最初の項目ではない(username,id,tried)ため、このインデックスを作成したクエリに効率的に使用することはできません。tried


マニュアルページからMySQLがインデックスを使用する方法

MySQLは、これらの操作にインデックスを使用します。

  • 特定のインデックス付き列のMIN()or値を検索します。これは、インデックスで以前に発生したすべての主要部分で使用しているかどうかをチェックするプリプロセッサによって最適化されます。この場合、MySQLはor式ごとに単一のキールックアップを実行し、それを定数に置き換えます。すべての式が定数に置き換えられると、クエリは一度に返されます。例えば:MAX()key_colWHERE key_part_N = constantkey_colMIN()MAX()

    SELECT MIN(key_part2)、MAX(key_part2)FROM tbl_name WHERE key_part1 = 10;

WHERE特に、句は、またはを計算する列の前にある列を参照する必要があることに注意してください。これが、現在のインデックスが効率的に使用されていない理由です。MINMAX


ループ内で選択クエリをすばやく実行する必要があります

ループでクエリを実行する必要がありますか?ループをデータベースに移動することを検討しましたか?たぶんあなたが本当に必要なのは参加ですか?それぞれ少量のデータのみをフェッチする多数の小さなクエリよりも、大量のデータをフェッチする単一のクエリを送信する方が適切です。

于 2012-06-15T17:15:12.730 に答える
2

列にインデックスを追加するとtried、クエリが高速化されます。MySQL は次の操作にインデックスを使用します。

特定のインデックス付き列 key_col の MIN() または MAX() 値を検索するには。これは、インデックス内の key_col の前に発生するすべてのキー部分で WHERE key_part_N = constant を使用しているかどうかをチェックするプリプロセッサによって最適化されます。この場合、MySQL は MIN() または MAX() 式ごとに単一のキー検索を行い、それを定数に置き換えます。すべての式が定数に置き換えられた場合、クエリはすぐに返されます。例えば:

SELECT MIN(key_part2),MAX(key_part2) FROM tbl_name WHERE key_part1=10;

于 2012-06-15T17:18:39.300 に答える
0

列にインデックスを追加するtriedと、クエリが高速化されます。

次のようなコマンドを使用できます

create index tried_ix1 on 04c1Tg0M (tried);

補足として、InnoDb テーブルにインデックスを適用する場合は、このインデックスをクラスター化する必要があるかどうかも検討してください。たとえば、特定の、おそらくソートされた順序で、おそらくレポートのために多くのテーブル レコードにアクセスする場合は、そのレポートのソート要件に基づいてクラスター化インデックスを作成することを検討してください。

于 2012-06-16T10:50:38.633 に答える