7

これは私の最初の投稿なので、1つのリンクしか投稿できないようです。そのため、参照しているサイトを下部にリストしました。一言で言えば、私の目標は、データベースが結果をより速く返すようにすることです。投稿の下部に質問を組み立てるのに役立つように、考えられる限り多くの関連情報を含めるようにしました。

マシン情報


8 processors
model name      : Intel(R) Xeon(R) CPU           E5440  @ 2.83GHz
cache size      : 6144 KB
cpu cores       : 4 

top - 17:11:48 up 35 days, 22:22, 10 users,  load average: 1.35, 4.89, 7.80
Tasks: 329 total,   1 running, 328 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.0%us,  0.0%sy,  0.0%ni, 87.4%id, 12.5%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   8173980k total,  5374348k used,  2799632k free,    30148k buffers
Swap: 16777208k total,  6385312k used, 10391896k free,  2615836k cached

ただし、私たちはmysqlインストールを256GBのRAMを搭載したクラスター内の別のマシンに移動することを検討しています。

テーブル情報


私のMySQLテーブルは次のようになります

CREATE TABLE ClusterMatches 
(
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    cluster_index INT, 
    matches LONGTEXT,
    tfidf FLOAT,
    INDEX(cluster_index)   
);

約1800万行あり、1Mの一意のcluster_indexと6Kの一意の一致があります。PHPで生成しているSQLクエリは次のようになります。

SQLクエリ


$sql_query="SELECT `matches`,sum(`tfidf`) FROM 
(SELECT * FROM Test2_ClusterMatches WHERE `cluster_index` in (".$clusters.")) 
AS result GROUP BY `matches` ORDER BY sum(`tfidf`) DESC LIMIT 0, 10;";

ここで、$ clusterには、約3,000のコンマ区切りのcluster_indexの文字列が含まれています。このクエリは約50,000行を使用し、実行に約15秒かかります。同じクエリを再度実行すると、実行に約1秒かかります。

使用法


  1. テーブルの内容は静的であると見なすことができます。
  2. 同時ユーザー数が少ない
  3. 上記のクエリは現在、テーブルで実行される唯一のクエリです

サブクエリ


この投稿[stackoverflow:MySQLでのサブクエリのキャッシュ/再利用] [1]とクエリ時間の改善に基づいて、サブクエリにインデックスを付けることができると思います。

mysql> EXPLAIN EXTENDED SELECT `matches`,sum(`tfidf`) FROM 
(SELECT * FROM ClusterMatches WHERE `cluster_index` in (1,2,...,3000) 
AS result GROUP BY `matches` ORDER BY sum(`tfidf`) ASC LIMIT 0, 10;

+----+-------------+----------------------+-------+---------------+---------------+---------+------+-------+---------------------------------+
| id | select_type | table                | type  | possible_keys | key           | key_len | ref  | rows  | Extra                           |
+----+-------------+----------------------+-------+---------------+---------------+---------+------+-------+---------------------------------+
|  1 | PRIMARY     |  derived2            | ALL   | NULL          | NULL          | NULL    | NULL | 48528 | Using temporary; Using filesort | 
|  2 | DERIVED     | ClusterMatches       | range | cluster_index | cluster_index | 5       | NULL | 53689 | Using where                     | 
+----+-------------+----------------------+-------+---------------+---------------+---------+------+-------+---------------------------------+

追加情報のこの古い記事[MySQLの最適化:クエリとインデックス] [2]によると、ここで見るのが悪いのは「一時的なものの使用」と「ファイルソートの使用」です。

MySQL構成情報


クエリキャッシュは利用可能ですが、サイズが現在ゼロに設定されているため、事実上オフになっています


mysqladmin variables;
+---------------------------------+----------------------+
| Variable_name                   | Value                |
+---------------------------------+----------------------+
| bdb_cache_size                  | 8384512              | 
| binlog_cache_size               | 32768                | 
| expire_logs_days                | 0                    |
| have_query_cache                | YES                  | 
| flush                           | OFF                  |
| flush_time                      | 0                    |
| innodb_additional_mem_pool_size | 1048576              |
| innodb_autoextend_increment     | 8                    |
| innodb_buffer_pool_awe_mem_mb   | 0                    |
| innodb_buffer_pool_size         | 8388608              |
| join_buffer_size                | 131072               |
| key_buffer_size                 | 8384512              |
| key_cache_age_threshold         | 300                  |
| key_cache_block_size            | 1024                 |
| key_cache_division_limit        | 100                  |
| max_binlog_cache_size           | 18446744073709547520 | 
| sort_buffer_size                | 2097144              |
| table_cache                     | 64                   | 
| thread_cache_size               | 0                    | 
| query_cache_limit               | 1048576              |
| query_cache_min_res_unit        | 4096                 |
| query_cache_size                | 0                    |
| query_cache_type                | ON                   |
| query_cache_wlock_invalidate    | OFF                  |
| read_rnd_buffer_size            | 262144               |
+---------------------------------+----------------------+

[Mysqlデータベースのパフォーマンスターニング][3]に関するこの記事に基づいて、調整する必要のある値は次のとおりです。

  1. table_cache
  2. key_buffer
  3. sort_buffer
  4. read_buffer_size
  5. record_rnd_buffer(GROUPBYおよびORDERBY用語の場合)

改善のために特定された領域-MySQLクエリの微調整


  1. 一致するデータ型を別のテーブルを指すintであるインデックスに変更する[MySQLは、TEXTやBLOBなどの可変長フィールドが含まれている場合、実際に動的行形式を使用します。この場合、並べ替えはディスク上で実行する必要があります。 。解決策は、これらのデータ型を避けることではなく、そのようなフィールドを関連するテーブルに分割することです。] [4]
  2. matchesステートメント["選択、グループ化、順序付け、または結合しているフィールドのインデックスを作成する必要があります。"] [5]に基づいて、 GROUPBYがより速く発生するように新しいmatch_indexフィールドにインデックスを付けます。

ツール


パフォーマンスを微調整するには、使用する予定です

  1. 【説明】【6】【出力フォーマット】【7】を参考に
  2. [ab-ApacheHTTPサーバーベンチマークツール][8]
  3. [プロファイリング][9]と[ログデータ][10]

将来のデータベースサイズ


目標は、1Mの一意のcluster_index値、1Mの一意の一致値、約0.5秒のクエリへの応答時間を持つ約3,000,000,000のテーブル行を持つことができるシステムを構築することです(必要に応じてramを追加し、データベースをクラスター全体に分散できます)

質問


  1. クエリがディスクに触れないように、レコードセット全体をRAMに保持したいと思います。データベース全体をMySQLキャッシュに保持すると、memcachedbが不要になりますか?
  2. データベース全体をMySQLキャッシュに保持しようとすると、永続的になるように設計されていないため、悪い戦略ですか?memcachedbやredisのようなものがより良いアプローチでしょうか?もしそうなら、なぜですか?
  3. クエリによって作成された一時テーブル「結果」は、クエリが終了すると自動的に破棄されますか?
  4. InnodbからMyISAMに切り替える必要があります[InnoDBは大量の書き込みに適しているのに対し、大量のデータの読み取りには適しています] [11]?
  5. [Query Cache Configuration] [12]でキャッシュがゼロとしてオンになっていないように見えますが、2回目に実行したときに、クエリが現在より速く発生するのはなぜですか?
  6. 「一時的な使用」と「ファイルソートの使用」の発生を排除するためにクエリを再構築できますか?サブクエリの代わりに結合を使用する必要がありますか?
  7. MySQL[データキャッシュ][13]のサイズをどのように表示しますか?
  8. 開始点として、table_cache、key_buffer、sort_buffer、read_buffer_size、record_rnd_bufferの値のどのようなサイズを提案しますか?

リンク


  • 1:stackoverflow.com/questions/658937/cache-re-use-a-subquery-in-mysql
  • 2:databasejournal.com/features/mysql/article.php/10897_1382791_4/Optimizing-MySQL-Queries-and-Indexes.htm
  • 3:debianhelp.co.uk/mysqlperformance.htm
  • 4:20bits.com/articles/10-tips-for-optimizing-mysql-queries-that-dont-suck/
  • 5:20bits.com/articles/10-tips-for-optimizing-mysql-queries-that-dont-suck/
  • 6:dev.mysql.com/doc/refman/5.0/en/explain.html
  • 7:dev.mysql.com/doc/refman/5.0/en/explain-output.html
  • 8:httpd.apache.org/docs/2.2/programs/ab.html
  • 9:mtop.sourceforge.net/
  • 10:dev.mysql.com/doc/refman/5.0/en/slow-query-log.html
  • 11:20bits.com/articles/10-tips-for-optimizing-mysql-queries-that-dont-suck/
  • 12:dev.mysql.com/doc/refman/5.0/en/query-cache-configuration.html
  • 13:dev.mysql.com/tech-resources/articles/mysql-query-cache.html
4

1 に答える 1

1

テーブルの変更


クエリによる順序付けとグループ化のためにインデックスを選択する方法に関するこの投稿のアドバイスに基づくと、テーブルは次のようになります。

CREATE TABLE ClusterMatches 
(
    cluster_index INT UNSIGNED, 
    match_index INT UNSIGNED,
    id INT NOT NULL AUTO_INCREMENT,
    tfidf FLOAT,
    PRIMARY KEY (match_index,cluster_index,id,tfidf)
);
CREATE TABLE MatchLookup 
(
    match_index INT UNSIGNED NOT NULL PRIMARY KEY,
    image_match TINYTEXT
);

サブクエリの削除

結果をSUM(tfidf)でソートしないクエリは次のようになります

SELECT match_index, SUM(tfidf) FROM ClusterMatches 
WHERE cluster_index in (1,2,3 ... 3000) GROUP BY match_index LIMIT 10;

これにより、一時的な使用とファイルソートの使用が不要になります

explain extended SELECT match_index, SUM(tfidf) FROM ClusterMatches 
WHERE cluster_index in (1,2,3 ... 3000) GROUP BY match_index LIMIT 10;
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+--------------------------+
| id | select_type | table                | type  | possible_keys | key     | key_len | ref  | rows  | Extra                    |
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+--------------------------+
|  1 | SIMPLE      | ClusterMatches       | range | PRIMARY       | PRIMARY | 4       | NULL | 14938 | Using where; Using index | 
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+--------------------------+

ソートの問題

ただし、ORDER BY SUM(tfdif)をに追加すると

SELECT match_index, SUM(tfidf) AS total FROM ClusterMatches
WHERE cluster_index in (1,2,3 ... 3000) GROUP BY match_index 
ORDER BY total DESC LIMIT 0,10;
+-------------+--------------------+
| match_index | total              |
+-------------+--------------------+
|         868 |   0.11126546561718 | 
|        4182 | 0.0238558370620012 | 
|        2162 | 0.0216601379215717 | 
|        1406 | 0.0191618576645851 | 
|        4239 | 0.0168981291353703 | 
|        1437 | 0.0160425212234259 | 
|        2599 | 0.0156466849148273 | 
|         394 | 0.0155945559963584 | 
|        3116 | 0.0151005545631051 | 
|        4028 | 0.0149106932803988 | 
+-------------+--------------------+
10 rows in set (0.03 sec)

結果はこのスケールでは適切に高速ですが、ORDER BY SUM(tfidf)があるということは、一時およびファイルソートを使用することを意味します

explain extended SELECT match_index, SUM(tfidf) AS total FROM ClusterMatches 
WHERE cluster_index IN (1,2,3 ... 3000) GROUP BY match_index 
ORDER BY total DESC LIMIT 0,10;
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+-----------------------------------------------------------+
| id | select_type | table                | type  | possible_keys | key     | key_len | ref  | rows  | Extra                                                     |
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+-----------------------------------------------------------+
|  1 | SIMPLE      | ClusterMatches       | range | PRIMARY       | PRIMARY | 4       | NULL | 65369 | Using where; Using index; Using temporary; Using filesort | 
+----+-------------+----------------------+-------+---------------+---------+---------+------+-------+-----------------------------------------------------------+

可能な解決策?

の行に沿って、一時的またはファイルソートを使用しないソリューションを探しています

SELECT match_index, SUM(tfidf) AS total FROM ClusterMatches 
WHERE cluster_index IN (1,2,3 ... 3000) GROUP BY cluster_index, match_index 
HAVING total>0.01 ORDER BY cluster_index;
合計のしきい値をハードコーディングする必要がない場合、アイデアはありますか?

于 2010-11-25T12:08:13.950 に答える