開発mysqlサーバーでクエリのパフォーマンスをテストするスクリプトをセットアップしようとしています。詳細は次のとおりです。
SELECT ... LIKE '%xy%'
)私がやりたいことは、他の変数に依存しない、単一のクエリの速度を測定するための信頼できるテスト環境を作成することです。
これまで、私は SQL_NO_CACHE を使用してきましたが、そのようなテストの結果は、キャッシュの動作を示す場合もあります。
誰かがこの振る舞いを詳細に説明できる場合は、SQL_NO_CACHE
; this の投稿で説明されているように、ファイルシステムキャッシュやクエリの実行に使用されるインデックスのキャッシュが原因である可能性があります。バッファプールとキーバッファがいつ無効になるか、またはそれらがどのようにテストに干渉する可能性があるかは明確ではありません。
では、mysqlサーバーを再起動する前に、1つのクエリのパフォーマンスが他のクエリよりも優れているかどうかを判断するのに信頼できる環境をセットアップするにはどうすればよいでしょうか。
LIKE操作自体を最適化できない場合は、チェックする必要のある行数を最小限にせずに基本クエリを最適化する必要があります。
そのために役立つかもしれないいくつかのこと:
EXPLAIN SELECT ...結果のrows
列。そして、
mysql> set profiling=1;
mysql> select sql_no_cache * from mytable;
...
mysql> show profile;
+--------------------+----------+
| Status | Duration |
+--------------------+----------+
| starting | 0.000063 |
| Opening tables | 0.000009 |
| System lock | 0.000002 |
| Table lock | 0.000005 |
| init | 0.000012 |
| optimizing | 0.000002 |
| statistics | 0.000007 |
| preparing | 0.000005 |
| executing | 0.000001 |
| Sending data | 0.001309 |
| end | 0.000003 |
| query end | 0.000001 |
| freeing items | 0.000016 |
| logging slow query | 0.000001 |
| cleaning up | 0.000001 |
+--------------------+----------+
15 rows in set (0.00 sec)
そして、
mysql> FLUSH STATUS;
mysql> select sql_no_cache * from mytable;
...
mysql> SHOW SESSION STATUS LIKE 'Select%';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| Select_full_join | 0 |
| Select_full_range_join | 0 |
| Select_range | 0 |
| Select_range_check | 0 |
| Select_scan | 1 |
+------------------------+-------+
5 rows in set (0.00 sec)
そして、もう1つの興味深い値はlast_query_cost
です。これは、オプティマイザがクエリを見積もるのにどれほどの費用がかかるかを示します(値はランダムページ読み取りの数です)。
mysql> SHOW STATUS LIKE 'last_query_cost';
+-----------------+-------------+
| Variable_name | Value |
+-----------------+-------------+
| Last_query_cost | 2635.399000 |
+-----------------+-------------+
1 row in set (0.00 sec)
MySQLのドキュメントはあなたの友達です。
このページ から引用:SQL_NO_CACHEオプションは、クエリキャッシュでのクエリ結果のキャッシュに影響します。テーブルが非常に小さい場合は、テーブル自体がすでにキャッシュされている可能性があります。テーブルではなく結果のキャッシュを回避するだけなので、説明されている動作が発生することがあります。したがって、他の投稿で述べたように、クエリの間に テーブルをフラッシュ する必要があります。
リンク先の記事に示されているように、テスト実行の間にFLUSH TABLES
を使用して、できる限りリセットします(特にクエリキャッシュ)。
複数のトライアルの全体的なパフォーマンスに興味を持つように、実際のパフォーマンス中にInnoDB自体が異なる状態になることをテストで考慮しないでください。トライアルごとにInnoDBをリセットしたい場合、パフォーマンステストはどの程度「本物」になりますか?再起動直後のパフォーマンスが低いために拒否するクエリは、InnoDBが少しウォームアップした後は、はるかに優れたクエリになる可能性があります。
私があなたなら、クエリオプティマイザーがInnoDBのパフォーマンスとは別に何をしているかに焦点を当てます。 InnoDBを調整する方法についてはたくさん書かれていますが、開始するための適切なクエリがあると役立ちます。
また、同等のMyISAMテーブルを使用してパフォーマンスを測定することもできます。この場合、FLUSH TABLES
は実際にはほとんど同一の開始点にリセットします。
クエリキャッシュを完全にオフにしてみましたか? SQL_NO_CACHEを使用しても、クエリキャッシュをオンにしているだけで約3%のペナルティがあります。
Maatkit の使用を検討しましたか?私が少し精通しているその機能の1つは、tcpdumpを使用してMySQLネットワークデータをキャプチャし、mk-query-digest
を使用してダンプを処理することです。このツールを使用すると、各クエリに関するいくつかの細かい詳細を表示できます。しかし、クエリ分析を容易にする他のツールがたくさんあります。
InnoDBでのフルテキストクエリは低速です(LIKE "%query%"ステートメント)。それらを最適化するために実行できることはありません。解決策は、クエリを実行している特定のテーブルをMyISAMに渡してフルテキストインデックス(innoDBはサポートしていません)を作成できることから、行を検索可能なインデックスに非正規化すること(推奨されません)、Doctrine ORMが提供するものまでさまざまです。これをアーカイブする簡単な例: http://www.doctrine-project.org/documentation/manual/1_1/nl/behaviors:core-behaviors:searchable 「適切な」ソリューション問題は、Sphinx SearchやApache Solrなどのソリューションを使用して、フルテキスト検索を使用して情報に索引を付けることです。
前に述べたように、結果を比較するときはキャッシュの状態を考慮する必要があります。準備されたキャッシュは非常にパフォーマンスの高いクエリを提供します。特定のクエリのキャッシュヒット率を考慮する必要があります。それが高価なクエリであっても、99%のキャッシュヒット率がある場合、平均パフォーマンスは非常に高くなります。
クエリのきめ細かい調整は特効薬ではありません。本番環境では全体的に無視できる最適化のために、アプリケーションに複雑さを追加している可能性があります。
ワークロードを考慮し、頻繁に実行されないクエリのトラブルシューティングを行います(mysqlでslow_query_logを使用し、盲目的にクエリの最適化を開始しないでください)。
あなたはmysqlワークベンチを試すことができます、それがSQLステートメントモニターを持っていると思ったので、それがどれほど速いか、なぜそれが速いのかを見ることができます