:: DEVELOPER ZONE
システム高速化のためのヒント(順不同)
接続オーバヘッドを回避するには、データベースに対して永続的な接続を使用する。永続的な接続を使用せずにデータベースに対して多数の新規接続を実行する場合は、thread_cache_size 変数の値の変更が必要になることがある。 See 項5.5.2. 「サーバパラメータのチューニング」。
常にすべてのクエリがテーブル内に作成したインデックスを実際に使用していることを確認する。MySQL では、EXPLAIN コマンドでこれを実行できる。 See 項5.2.1. 「EXPLAIN 構文(SELECT に関する情報の取得)」。
大量に更新された MyISAM テーブルに対して複雑な SELECT クエリを使用しないようにする。これでテーブルロックを回避する。
削除されたレコードがない MyISAM テーブルの場合は、別のクエリでそのテーブルからの読み取りが行われるのと同時にレコードを挿入できる。これがあなたにとって重要ならば、レコードの削除が不要なメソッドや、大量のレコード削除後の OPTIMIZE TABLE の実行を検討する。
expr1,expr2... の順に従って頻繁にレコードを読み取る場合は、ALTER TABLE ... ORDER BY expr1,expr2... を使用する。テーブルが大幅に変更された後にこのオプションを使用すると、パフォーマンスを改善できる。
他のカラムの情報を基にした 'ハッシュされた' カラムを導入することが役立つ場合がある。このカラムが短いもので、一意性がある場合は、多数のカラムに大きなインデックスを使用するより大幅に高速化できる。MySQL では、追加カラムの使用が以下のように非常に容易である。
SELECT * FROM table_name WHERE hash=MD5(CONCAT(col1,col2)) AND col_1='constant' AND col_2='constant'
大量に変更があるテーブルはすべて VARCHAR や BLOB のカラムを使用しないようにする。VARCHAR または BLOB カラムを 1 つ使用するとレコードがただちに可変長になってしまう。 See 章 7. MySQL のテーブル型。
一般に、1 つのテーブルを複数のテーブルに分割することは、レコードが '大きく' なるだけで高速化の役には立たない。レコードにアクセスする際の、最も大きなパフォーマンス要因は、レコードの最初のバイトを見つけるためのディスクシークである。データの検索後、ほとんどの新規ディスクでは、大多数のアプリケーションに十分な速度でレコード全体を読み取ることができる。テーブルの分割が実際に有効な状況は、固定長テーブルへの変更が可能な可変長テーブル(上記参照)の場合か、テーブルのスキャンを非常に頻繁に必要としながらもほとんどのカラムを結果に必要としない場合のみである。 See 章 7. MySQL のテーブル型。
多数のレコードの情報から計算する頻度を非常に高くする必要がある場合(カウントの場合など)、新たなテーブルを導入し、リアルタイムでカウンタを更新するほうがはるかに適している。UPDATE table SET count=count+1 WHERE index_column=constant のような更新は非常に高速にできる。
実際これは、MyISAM や ISAM のようにテーブルロック(複数リーダ/単一ライタ)のみの MySQL テーブル型を使用する場合に非常に重要である。また、このような場合は行ロックマネージャで必要な作業が少なくなるため、ほとんどのデータベースでパフォーマンスが改善される。
大きなログテーブルから統計を収集する必要がある場合は、テーブル全体をスキャンするのではなく、サマリテーブルを使用する。サマリの管理は、リアルタイムで統計を実行する場合と比較して非常に高速になる。何らかの変更がある(業務上の決定に応じて)場合は、ログから新規にサマリテーブルを再生成したほうが、実行アプリケーションの変更よりはるかに高速である。
可能であれば、レポートをリアルタイムか集計かのいずれかに分類するように推奨する。集計レポートに必要なデータは、サマリテーブルから生成され、サマリテーブルは実データから生成される。
カラムにデフォルト値がある利点を生かす。挿入対象の値がデフォルト値と相違する場合のみ明示的に値を挿入する。これで、MySQL が要する解析作業が軽減され、挿入の速度が改善される。
状況によっては、データを BLOB にパックし、格納したほうが便利である。このような場合は、BLOB へのパックおよびパック解除を行うコードをアプリケーションに追加する必要があるが、あるステージにおける大量のアクセスを省略できることになる。 これは、固定長テーブル構造に準拠しないデータがある場合に実用的である。
通常は、すべてのデータが冗長にならないようにする必要がある(データベースセオリの第 3 正規化)が、高速化を図る必要がある場合はデータなどの複製やサマリテーブルの作成をためらうべきではない。
ストアドプロシージャや UDF(ユーザ定義関数)はパフォーマンスの向上に役立つ手段である。ただし、これをサポートしないデータベースを使用する場合は、常に代替の(速度が遅い)方法も用意する必要がある。
アプリケーションのクエリと応答をキャッシュすること、および挿入と更新の同時実行を試行することは必ず高速化に役立つ。データベースでロックテーブルがサポートされる場合(MySQL や Oracle など)は、これによって確実にすべての更新後にインデックスキャッシュが 1 回だけフラッシュされるようにできる。
データの書き込みするタイミングを知る必要がない場合は、INSERT /*! DELAYED */ を使用する。多数のレコードが 1 回のディスクへの書き込みで書き込まれるため、これで高速化が図れる。
SELECT の優先を上げる場合は、INSERT /*! LOW_PRIORITY */ を使用する。
SELECT がキューをジャンプするようにする場合は、SELECT /*! HIGH_PRIORITY */ を使用する。言い換えると、書き込み待機中のユーザがいる場合でも、SELECT を実行できるようになる。
1 つの SQL コマンドで多数のレコードを格納するには、複数行の INSERT ステートメントを使用する(これは多数の SQL でサポートされている)。
大量のデータをロードする場合は LOAD DATA INFILE を使用する。これは通常の挿入より高速になる。
一意の値にするには AUTO_INCREMENT カラムを使用する。
一定の間隔で OPTIMIZE TABLE を使用して、動的テーブルの断片化を回避する。 See 項4.6.1. 「OPTIMIZE TABLE 構文」。
可能ならば HEAP を使用して高速化を図れるようにする。 See 章 7. MySQL のテーブル型。
通常の Web サーバセットアップを使用する場合は、画像をファイルとして格納する。言い換えると、データベース内にはファイル参照のみを格納する。この主な理由は、通常の Web サーバのほうがデータベースコンテンツと比較してファイルのキャッシュに優れているためである。このため、ファイルを使用したほうがシステムの高速化を容易に図れる。
頻繁にアクセスされる非クリティカルデータ(クッキーなしでユーザに最後に表示されたバナーの情報など)にはメモリテーブルを使用する。
別のテーブルで同一情報を扱うカラムは、同じ宣言をし、同じ名前を付ける。バージョン 3.23 以前はこのようにしないと結合の速度が遅くなる。
名前はなるべく単純なものに保持する(カスタマテーブルでは customer_name ではなく name を使用する)。他の SQL サーバに移植可能にすることを考慮するなら、名前を 18 文字未満にする。
高速化が大きく必要とされる場合は、複数の SQL サーバがサポートするデータストレージの低レベルインタフェースを調べる必要がある。たとえば、MySQL MyISAM に直接アクセスすることによって、SQL インタフェース使用時と比較して 2-5 倍の速度が得られることもある。
これを実行可能にするには、データをアプリケーションと同じサーバに配置し、また通常は 1 プロセスのみからアクセスするようにする必要がある(外部ファイルロックが非常に低速なため)。上記の問題は、MySQL サーバに低レベルの MyISAM コマンドを導入することで解消できる(必要に応じてパフォーマンスを改善する容易な手段の 1 つ)。データベースインタフェースを慎重に設計することで、この種の最適化を容易にサポートできる。
多くの場合、テキストファイルにアクセスするのと比較して、データベースからデータにアクセスしたほうが高速である。この理由は一般にテキストファイル(数値データ使用時)よりデータベースのほうがよりコンパクトで、必要なディスクアクセスが少ないことによる。また、テキストファイルを解析してレコードとカラムの境界を検索する必要がないため、コードも節約できる。
レプリケーションでも高速化を図ることができる。 See 項4.11. 「MySQL のレプリケーション」。
DELAY_KEY_WRITE=1 オプションでテーブルを定義すると、ファイルが閉じられるまでディスクにログが記録されないためインデックス更新の速度が上がる。
この欠点は、途中で mysqld の強制終了が発生した場合にテーブルに問題がないことを確認するため、mysqld を開始する前に、テーブルに対して myisamchk を実行する必要があるということである。キー情報は常にデータから生成可能であるため、DELAY_KEY_WRITE を使用しても何も消失はしない。
© 1995-2005 MySQL AB. All rights reserved.
