付録 E. 他システムへの移植

目次

E.1. MySQL サーバのデバッグ
E.1.1. MYSQL のコンパイル(デバッグ用)
E.1.2. トレースファイルの作成
E.1.3. mysqld のデバッグ(gdb 使用)
E.1.4. スタックトレースの使用
E.1.5. mysqld におけるエラーの原因をログファイルを使用して特定する
E.1.6. テーブルが破損した場合にテストケースを作成する
E.2. MySQL クライアントのデバッグ
E.3. DBUG パッケージ
E.4. ロック方法
E.5. RTS スレッドに関するコメント
E.6. 異なったスレッドパッケージ間の差異

この付録は、MySQL を他のオペレーティングシステムに移植する際に役立ちます。 現時点でサポートされているオペレーティングシステムの一覧を最初に確認してください。 See 項2.2.3. 「MySQL がサポートしているオペレーティングシステム」。 MySQL の移植版を新たに作成した場合はお知らせください。このマニュアルと当社 Web サイト(http://www.mysql.com/)に新規移植版を掲載し、他のユーザに推奨させていただきます。

注意: 作成した MySQL 移植版は GPL ライセンスの下で自由に複製および配布することができますが、これによって MySQL の所有権が付与されるものではありません。

移植先のサーバには、有効な Posix スレッドライブラリが必要です。我々は、Solaris 2.5 については Sun の PThread(2.4 以前のバージョンにおけるネイティブスレッドのサポートは不十分でした)、Linux については Xavier Leroy()による LinuxThread を使用しています。

ネイティブスレッドに関する十分なサポートがない状態で新種の Unix に移植する際に難しいのは、MIT-pthread の移植であると考えられます。mit-pthreads/README と「Programming POSIX Threads」(http://www.humanfactor.com/pthreads/)を参照してください。

MySQL 4.0.2 まで、MySQL のディストリビューションには Chris Provenzano の MIT Pthread(MIT Pthread の Web ページ(http://www.mit.edu/afs/sipb/project/pthreads/)と プログラミング入門(http://www.mit.edu:8001/people/proven/IAP_2000/))パッチ適用バージョンが含まれていました。 これらは POSIX スレッドを持たない一部のオペレーティングシステムでも使用可能です。 See 項2.3.6. 「MIT-pthreads に関する注意事項」

別のユーザレベルスレッドパッケージである FSU Pthread (http://moss.csc.ncsu.edu/~mueller/pthreads/ を参照)を使用することもできます。 この実装は SCO への移植に使用されています。

これらの問題のテストや実例については、mysys ディレクトリの thr_lock.c および thr_alarm.c プログラムを参照してください。

サーバとクライアントのどちらにも C++ コンパイラが必要です。我々は、多くのプラットフォームで gcc を使用しています。上記以外で有効と確認されたコンパイラは、SPARCworks、Sun Forte、Irix cc、HP-UX aCC、IBM AIX xlC_r)、Intel ecc、Compaq cxx) です。

クライアントのみコンパイルするには、./configure --without-server を使用します。

サーバのみのコンパイルは、現時点ではサポートされておらず、格別の理由がない限り追加されないものと思われます。

Makefile または configure スクリプトを変更する必要がある場合、GNU Automake および Autoconf も必要です。 See 項2.3.4. 「開発ソースツリーからのインストール」

最も基本的なファイルからすべてを再作成するために必要な手順。

/bin/rm */.deps/*.P
/bin/rm -f config.cache
aclocal
autoheader
aclocal
automake
autoconf
./configure --with-debug=full --prefix='your installation directory'

# The makefiles generated above need GNU make 3.75 or newer.
# (called gmake below)
gmake clean all install init-db

移植に関して問題が起きた場合、MySQL をデバッグしなければならないことがあります。 See 項E.1. 「MySQL サーバのデバッグ」

注意: mysqld のデバッグを開始する前に、テストプログラム mysys/thr_alarm および mysys/thr_lock を起動してください。これによって、スレッドのインストールが実行される可能性も多少あります。

E.1. MySQL サーバのデバッグ

MySQL の新機能を使用している場合、以下を指定して mysqld の実行を試みることができます。--skip-new を指定すると、安全でない可能性のある新機能がすべて無効になります。--safe-mode を指定すると、問題を引き起こす可能性のある最適化の大部分が無効になります。 See 項A.4.1. 「MySQL が何度もクラッシュする場合に行うこと」

mysqld が起動しない場合、いずれかの my.cnf ファイルがセットアップの妨げとなっていないか確認する必要があります。 my.cnf 引数を mysqld --print-defaults でチェックし、これらの引数が使用されないように、mysqld --no-defaults ... で起動することができます。

mysqld がCPU またはメモリを消費し始めたか ``ハング'' した場合、mysqladmin processlist status を使用して、時間のかかるクエリを実行しているユーザを確認することができます。mysqladmin -i10 processlist status をウィンドウで実行すると有益なケースもあります。たとえば、新しいクライアントに接続できないときにパフォーマンスの問題が起きている場合です。

コマンド mysqladmin debug を実行すると、使用中のロック、メモリの使用容量、およびクエリの用途に関する情報が mysql ログファイルにダンプされ、問題解決につながることがあります。また、デバッグのために MySQL をコンパイルしていなくても、有益な情報を得られることもあります。

一部のテーブルの処理速度が低下する問題が起きた場合、OPTIMIZE TABLE または myisamchk でテーブルの最適化を試みてください。See 章?4. データベース管理。 また、遅いクエリを EXPLAIN でチェックする必要があります。

このマニュアルにおける OS 固有のセクションを参照し、使用環境に特有な問題について確認する必要もあります。 See 項2.6. 「オペレーティングシステム固有の注意事項」

E.1.1. MYSQL のコンパイル(デバッグ用)

極めて固有な問題が起きた場合は、いつでも MySQL のデバッグを試みることができます。デバッグするには、--with-debug または --with-debug=full オプションを指定して MySQL を設定する必要があります。 MySQL がコンパイルされたかどうかをチェックするには、mysqld --help を実行します。--debug オプションが表示されたらデバッグは有効です。この場合、mysqladmin ver を実行すると、mysqld バージョンが mysql ... --debug として表示されます。

gcc または egcs の使用時には、以下の configure 行が推奨されています。

CC=gcc CFLAGS="-O2" CXX=gcc CXXFLAGS="-O2 -felide-constructors \
   -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql \
   --with-debug --with-extra-charsets=complex

これによって、libstdc++ ライブラリと C++ 例外に関する問題が回避され(多くのコンパイラでは、スレッドコードで C++ 例外が発生します)、すべてのキャラクタセットのサポート付きで MySQL がコンパイルされます。

メモリオーバーランエラーの疑いがある場合、--with-debug=full オプションを指定して MySQL を設定し、メモリ割当(SAFEMALLOC)チェッカをインストールできます。ただし、SAFEMALLOC を指定して実行すると非常に遅くなるので、パフォーマンスの問題が生じたときには mysqld--skip-safemalloc オプションで起動してください。これによって、malloc()free() に対する呼び出しのたびにメモリオーバーランのチェックが無効になります。

mysqld--with-debug 付きのコンパイル時にクラッシュしなくなった場合、コンパイラバグまたはタイミングバグが MySQL で検出されたと考えられます。この場合、上記の CFLAGS および CXXFLAGS 変数に -g を追加し、--with-debug を指定しない方法を試みることができます。mysqld がクラッシュした場合、少なくとも gdb を使用してアタッチするか、コアファイル上で gdb を実行して何が起きたか確認することは可能です。

デバッグ用に MySQL を設定すると、多くの特別なチェック関数が自動的に有効になり、これらによって mysqld の状態が監視されます。 ``予期しない'' 状態が検出された場合、stderr にエントリが書き込まれ、mysqld_safe によってエラーログに送信されます。つまり、予期しない問題が MySQL で発生したときにソースディストリビューションを使用している場合、まず MySQL をデバッグ用に設定する必要があります。その後は MySQL メーリングリストにメールを送信し、ヘルプを依頼してください。 See 項1.7.1.1. 「MySQL メーリングリスト」。 ご利用の MySQL バージョンに関するバグレポートまたは質問については、mysqlbug を使用してください。

Windows 版 MySQL ディストリビューションでは、mysqld.exe がデフォルトでコンパイルされています(トレースファイルのサポート付き)。

E.1.2. トレースファイルの作成

mysqld サーバが起動しないか mysqld サーバですぐにクラッシュが起きる場合、トレースファイルを作成して問題の検出を試みることができます。

そのためには、mysqld をデバッグ用にコンパイルしておく必要があります。そのようにコンパイルされているか確認するには、mysqld -V を実行します。バージョン番号の末尾が -debug である場合、トレースファイルのサポート付きでコンパイルされています。

/tmp/mysqld.trace(Windows では C:\mysqld.trace)内のトレースログを指定して mysqld サーバを起動します。

mysqld --debug

Windows では、--standalone フラグを使用し、mysqld がサービスとして起動されないようにする必要もあります。

コンソールウィンドウで以下を実行します。

mysqld --debug --standalone

この後、mysql.exe コマンドラインツールを 2 番目のコンソールウィンドウで実行し、問題を再現することができます。mysqladmin shutdown では、mysqld サーバを強制終了することができます。

注意: トレースファイルは非常に大きなサイズになります。 トレースファイルのサイズを小さくしたい場合、たとえば以下のように指定することができます。

mysqld --debug=d,info,error,query,general,where:O,/tmp/mysqld.trace

(この場合、最も興味深いタグの付いた情報のみが /tmp/mysqld.trace に出力されます。)

これに関するバグレポートを作成する場合、不具合があると思われる行のみをトレースファイルから選択し、適切なメーリングリスト宛てに送信してください。不具合の場所を特定できない場合には、トレースファイルと完全なバグレポートを ftp://support.mysql.com/pub/mysql/secret/ まで ftp で送信してください。MySQL の開発者側で確認させていただきます。

トレースファイルは、Fred Fish による DBUG パッケージで作成されています。 See 項E.3. 「DBUG パッケージ」

E.1.3. mysqld のデバッグ(gdb 使用)

多くのシステムでは、mysqld がクラッシュした際に、mysqldgdb から起動することで、より多くの情報を取得することもできます。

Linux で使用される旧バージョンの gdb の一部では、mysqld スレッドをデバッグする際に run --one-thread を使用しなければなりません。この場合、一度にアクティブにできるスレッドは 1 つだけです。速やかに gdb 5.1 にアップグレードすることをお奨めします。このバージョンでは、スレッドデバッグの処理が大幅に改善されるからです。

gdb で mysqld を実行する場合、スタックトレースを --skip-stack-trace で無効化し、gdb 内部で segfault を捕捉できるようにする必要があります。

MySQL 4.0.14 以降では、mysqld に対して --gdb オプションを使用してください。このオプションを使用すると、SIGINT(mysqld を ^C で終了し、ブレークポイントを設定するために必要)の割り込みハンドラがインストールされ、スタックトレースとコアファイル処理が無効になります。

gdb で MySQL をデバッグするのが非常に困難な場合があります。たとえば、古いスレッドに対するメモリが gdb によって解放されず、デバッグ中に大量の新規接続を連続して確立しなければならない場合です。この問題を回避するには、-O thread_cache_size= 'max_connections +1' を指定して mysqld を起動します。多くの場合、-O thread_cache_size=5' を指定するだけで状況は大幅に改善します。

SIGSEGV シグナルで mysqld がクラッシュした場合、Linux 上でコアダンプを取得するには、--core-file オプションを指定して mysqld を起動します。 このコアファイルを使用してバックトレースを作成し、mysqld がクラッシュした理由を特定することもできます。

shell> gdb mysqld core
gdb>   backtrace full
gdb>   exit

See 項A.4.1. 「MySQL が何度もクラッシュする場合に行うこと」

gdb 4.17.x 以降を Linux で使用している場合、.gdb ファイルを以下の情報と共にカレントディレクトリにインストールする必要があります。

set print sevenbit off
handle SIGUSR1 nostop noprint
handle SIGUSR2 nostop noprint
handle SIGWAITING nostop noprint
handle SIGLWP nostop noprint
handle SIGPIPE nostop
handle SIGALRM nostop
handle SIGHUP nostop
handle SIGTERM nostop noprint

gdb でスレッドのデバッグに問題が起きた場合、gdb 5.x をダウンロードして代用してみてください。gdb の新規バージョンでは、スレッドの処理が飛躍的に改善されています。

以下の例は、mysqld をデバッグする方法を示します。

shell> gdb /usr/local/libexec/mysqld
gdb> run
...
backtrace full # Do this when mysqld crashes

mysqlbug で生成された上記の出力内容をメールに取り込み、通常の MySQL メーリングリスト宛てに送信してください。 See 項1.7.1.1. 「MySQL メーリングリスト」

mysqld がハングした場合、strace/usr/proc/bin/pstack のようなシステムツールを使用し、mysqld がハングした場所を調べることができます。

strace /tmp/log libexec/mysqld

Perl DBI インタフェースを使用している場合、デバッグ情報を有効にするには、trace メソッドを使用するか DBI_TRACE 環境変数を設定します。 See 項11.5.2. 「DBI インタフェース」

E.1.4. スタックトレースの使用

一部のオペレーティングシステムでは、mysqld が突然クラッシュするとスタックトレースがエラーログに記録されます。この情報を使用すると、mysqld がクラッシュした場所(および理由)を確認することができます。See 項4.10.1. 「エラーログ」。 スタックトレースを取得する場合、mysqld のコンパイルを -fomit-frame-pointer オプション付き gcc で行わないでください。 See 項E.1.1. 「MYSQL のコンパイル(デバッグ用)」

エラーファイルの内容が以下のとおりであるとします。

mysqld got signal 11;
The manual section 'Debugging a MySQL server' tells you how to use a
stack trace and/or the core file to produce a readable backtrace that may
help in finding out why mysqld died
Attemping backtrace. You can use the following information to find out
where mysqld died.  If you see no messages after this, something went
terribly wrong
stack range sanity check, ok, backtrace follows
0x40077552
0x81281a0
0x8128f47
0x8127be0
0x8127995
0x8104947
0x80ff28f
0x810131b
0x80ee4bc
0x80c3c91
0x80c6b43
0x80c1fd9
0x80c1686

mysqld がクラッシュした場所を特定するには、以下を実行します。

  1. 上記の番号をファイル(たとえば mysqld.stack)にコピーする。

  2. mysqld サーバのシンボルファイルを作成する。

    nm -n libexec/mysqld > /tmp/mysqld.sym
    

    注意: 多くの MySQL バイナリディストリビューション(この情報がバイナリ自体の内部に含まれている "デバッグ" パッケージは除外)には、上記のファイルが mysqld.sym.gz という名称で同梱されています。 ここでは、このファイルを以下のように簡単に解凍できます。

    gunzip < bin/mysqld.sym.gz > /tmp/mysqld.sym
    
  3. resolve_stack_dump -s /tmp/mysqld.sym -n mysqld.stack を実行する。

    実行すると、mysqld がクラッシュした場所が出力されます。mysqld がクラッシュした原因をこの方法で特定できない場合には、バグレポートを作成し、上記コマンドの出力結果をバグレポートに含める必要があります。

    ただし、多くの場合、スタックトレースだけでは問題の理由を特定できません。バグを見つけるか次善策を講じるには、多くの場合、mysqld のクラッシュを引き起こしたクエリのほか、可能であれば問題を再現できるテストテースについても知る必要があります。 See 項1.7.1.3. 「バグまたは問題を報告する方法」

E.1.5. mysqld におけるエラーの原因をログファイルを使用して特定する

注意: --log を指定して mysqld を起動する前に、すべてのテーブルを myisamchk でチェックしてください。 See 章?4. データベース管理

mysqld がクラッシュまたはハングした場合、--log を指定して mysqld を起動する必要があります。mysqld が再度クラッシュした場合、ログファイルの末尾を参照し、mysqld のクラッシュを引き起こしたクエリの有無を確認できます。

ファイル名なしで --log を使用している場合、ログは 'hostname'.log としてデータベースディレクトリに格納されます。多くの場合、ログファイル内の最後のクエリが原因で mysqld がクラッシュしています。ただし、実際にそうであったかどうかを確認するため、mysqld を再起動し、検出されたクエリを mysql コマンドラインツールから実行する必要があります(可能な場合)。この方法が有効な場合、完了しなかった複雑なクエリをすべてテストする必要もあります。

時間がかかる SELECT ステートメントのすべてに対してコマンド EXPLAIN を実行し、インデックスが mysqld によって適切に使用されているかどうかを確認することもできます。 See 項5.2.1. 「EXPLAIN 構文(SELECT に関する情報の取得)」

実行時間の長いクエリを検索するには、--log-slow-queries を指定して mysqld を実行します。 See 項4.10.5. 「スロークエリログ」

テキスト mysqld restarted がエラーログファイル(通常は hostname.err という名称)に含まれている場合、mysqld のクラッシュを引き起こしたクエリが検出されたと考えられます。この場合、myisamchk(see 章?4. データベース管理)でテーブルをすべてチェックします。また、MySQL ログファイル内のクエリをテストし、いずれかが無効かどうかを確認します。そのようなクエリが見つかった場合、最新バージョンの MySQL へのアップグレードを試みてください。アップグレードしても問題が解決せず、mysql メールアーカイブにも有益な情報がない場合、MySQL メーリングリストにバグをレポートする必要があります。 このメーリングリストが掲載されている http://lists.mysql.com/ には、オンラインリストアーカイブもリンクされています。

myisam-recover を指定して mysqld を起動した際、MyISAM テーブルが '正しく閉じられなかった' または 'クラッシュした' とマークされている場合、そのテーブルは自動的にチェックされ、修復が試行されます。この場合、hostname.err ファイルに 'Warning: Checking table ...' と書き込まれます。また、テーブルの修復が必要であれば、Warning: Repairing table が続いて書き込まれます。これらのエラーが大量に発生した際、直前に mysqld が突然クラッシュしていない場合は異常であり、さらに調査しなければなりません。 See 項4.1.1. 「mysqld コマンドラインオプション」

mysqld が突然クラッシュするのは、もちろん正常ではありません。ただし、その場合には、Checking table... メッセージを調べるのではなく、mysqld がクラッシュした原因を探してください。

E.1.6. テーブルが破損した場合にテストケースを作成する

テーブルが破損しているか、更新コマンドの後に mysqld が必ずエラーになる場合、この問題が再現されるかテストするには以下を実行します。

  • MySQL デーモンを強制終了する(mysqladmin shutdown を使用)。

  • テーブルのバックアップを作成する(修復による悪影響が生じた場合に備えるため)。

  • すべてのテーブルを myisamchk -s database/*.MYI でチェックする。問題の起きたテーブルがあれば myisamchk -r database/table.MYI で修復する。

  • テーブルの 2 次バックアップを作成する。

  • 空き容量を増やす必要がある場合、古いログファイルを MySQL データディレクトリから削除または移動する。

  • mysqld--log-bin で起動する。 See 項4.10.4. 「バイナリログ」mysqld のクラッシュを引き起こすクエリを検索する場合、--log --log-bin を使用する。

  • テーブルがクラッシュした場合、mysqld server を終了する。

  • バックアップをリストアする。

  • --log-bin指定しないmysqld サーバを起動する。

  • mysqlbinlog update-log-file | mysql を指定してコマンドを再実行する。 更新ログは、hostname-bin.# という名称で MySQL データベースディレクトリに保存される。

  • テーブルが再度破損したか、上記のコマンドで mysqld が終了する場合、再現可能なバグが検出されている。そのようなバグは、容易に修正することが可能。テーブルとバイナリログを ftp://support.mysql.com/pub/mysql/secret/ FTP で送信し、当社のバグシステム(http://bugs.mysql.com/)に入力する。 サポートユーザの場合、 で MySQL チームに問題を通知し、迅速な修正を依頼することもできる。

スクリプト mysql_find_rows で一部の更新ステートメントのみを実行し、問題を絞り込むこともできます。

E.2. MySQL クライアントのデバッグ

MySQL クライアントを統合デバッグパッケージによってデバッグするには、--with-debug または --with-debug=full を指定して MySQL を設定する必要があります。 See 項2.3.3. 「一般的な configure オプション」

クライアントを実行する前に、MYSQL_DEBUG 環境変数を指定してください。

shell> MYSQL_DEBUG=d:t:O,/tmp/client.trace
shell> export MYSQL_DEBUG

その結果、クライアントによってトレースファイルが /tmp/client.trace に生成されます。

ユーザ自身のクライアントコードで問題が起きた場合、サーバに接続し、有効と確認されているクライアントでクエリを実行してみてください。そのためには、mysql をデバッグモードで実行します(デバッグを有効にして MySQL をコンパイルしてあることが前提)。

shell> mysql --debug=d:t:O,/tmp/client.trace

バグレポートをメール送信する場合、上記によって有益な情報を得ることができます。 See 項1.7.1.3. 「バグまたは問題を報告する方法」

'有効と思われる' コードでクライアントがクラッシュした場合、mysql.h インクルードファイルが mysql ライブラリファイルと一致するかどうかを確認する必要があります。 一般的な誤りとしては、古いバージョンの MySQL の mysql.h ファイルを新しい MySQL ライブラリと共に使用することがあります。

E.3. DBUG パッケージ

MySQL サーバと多くの MySQL クライアントは、DBUG パッケージ(オリジナル開発者は Fred Fish)によってコンパイルされています。デバッグ用に MySQL を設定した場合、デバッグされている内容に関するトレースファイルを取得できます。 See 項E.1.2. 「トレースファイルの作成」

デバッグパッケージを使用するには、--debug="..." または -#... オプションを指定してプログラムを起動します。

多くの MySQL プログラムにはデフォルトのデバッグ文字列があり、--debug に対してオプションを指定しなかった場合に使用されます。デフォルトのトレースファイルは通常、Unix では /tmp/programname.trace、Windows では \programname.trace です。

デバッグコントロール文字列は、以下のようにコロンで区切られた一連のフィールドです。

<field_1>:<field_2>:...:<field_N>

各フィールドの構成要素は、フラグ文字列(必須)と、後続する "," およびコンマ区切り修飾子一覧(任意)です。

flag[,modifier,modifier,...,modifier]

現時点で認識されるフラグ文字は以下のとおりです。

フラグ説明
d現在の状態に対して DBUG_<N> マクロからの出力を有効にする。キーワードを伴う DBUG マクロに関する出力のみが選択されるキーワード一覧が後続する場合がある。キーワード一覧が空白になっている場合、すべてのマクロに関する出力であることを示す。
D各デバッガ出力行の後の遅延。引数は遅延する時間(1/10 秒単位の数)。マシンの性能によって異なる。つまり、-#D,20 は 2 秒遅延することを示す。
fデバッグとトレースの一方または両方を制限し、指定された関数の一覧にプロファイルを設定する。注意: 一覧が空白になっている場合、すべての関数が無効になる。適切な "d" または "t" フラグの指定が依然として必要。このフラグによって関数の動作が制限されるのは、関数が有効になっている場合に限られる。
Fデバッグまたはトレース出力の各行に対応したソースファイル名を識別する。
iデバッグまたはトレース出力の各行に対応した PID またはスレッド ID を持つプロセスを識別する。
gプロファイルを有効にする。プログラムのプロファイルに使用できる情報を含むファイル 'dbugmon.out' を作成する。一覧の関数のみに対してプロファイルを選択するキーワードの一覧が後続する場合がある。一覧が空白になっている場合、すべての関数が考慮される。
Fデバッグまたはトレース出力の各行に対応したソースファイル行番号を識別する。
nデバッグまたはトレース出力の各行に対応した現在の関数のネスト深度を印刷する。
Ndbug 出力の各行に番号を設定する。
oデバッガ出力ストリームを指定ファイルにリダイレクトする。デフォルト出力は stderr である。
Oo と同様。ただし、書き込みのたびにファイルが実際にフラッシュされる。必要に応じて、ファイルは閉じられ、各書き込みの間に再度開かれる。
pデバッガの操作を指定プロセスに制限する。プロセスは、DBUG_PROCESS マクロで識別され、実行されるデバッガ操作の一覧に含まれるものと一致しなければならない。
Pデバッグまたはトレース出力の各行に対応した現在のプロセス名を印刷する。
r新しいステータスに移行する際に、以前のステータスの関数ネストレベルを継承しない。.出力の開始位置が左マージンである場合に有効。
S0 以外の値が _sanity() から返されるまで、デバッグ対象の各関数で関数 _sanity(_file_,_line_) を実行する(メモリリークを検出するために safemalloc と共に使用されることが多い)。
t関数呼び出しの有効化/トレース行の終了。最大トレースレベルを数値で指定する一覧(修飾子が 1 つだけ含まれている)が後続する場合がある。このレベルを超えると、デバッグマクロとトレースマクロのいずれに対しても出力は実行されない。デフォルトはコンパイル時間オプションである。

シェルコマンドラインに表示されるデバッグコントロール文字列("-#" の一般的な用途は、アプリケーションプログラムに対するコントロール文字列の導入)の例を以下に示します。

-#d:t
-#d:f,main,subr1:F:L:t,20
-#d,input,output,files:n
-#d:t:i:O,\\mysqld.trace

MySQL で出力するための一般的なタグ(d オプション付き)は、enterexiterrorwarninginfoloop です。

E.4. ロック方法

ISAM/MyISAM および HEAP テーブルのテーブルロック、BDB テーブルのページレベルロック、InnoDB テーブルの行レベルロックのみが、MySQL で現在サポートされています。 See 項5.3.1. 「MySQL のテーブルロック方法」INSERT ステートメント間に競合がない場合(レコードまたはデータの削除による空き領域を埋めるのではなく、テーブルファイル末尾に追加する場合はいつでも)、MyISAM テーブルでは INSERTSELECT をロックなしで自由に組み合わせることができます。

バージョン 3.23.33 からは、システムにおけるテーブルロックの競合を Table_locks_waited および Table_locks_immediate 環境変数を確認して分析できるようになりました。

テーブル型を行レベルロックと共に使用するかどうかを決定するには、アプリケーションの処理内容とデータの選択/更新パターンを確認する必要があります。

行ロックの利点:

  • 多数のスレッド内の異なったレコードにアクセスする際にロックの競合が少ない。

  • ロールバックの変更が少ない。

  • 単一レコードを長時間ロックすることができる。

行ロックの欠点:

  • ページレベルロックまたはテーブルロックよりも多くのメモリを消費する。

  • テーブルの広範囲で実行する場合、多数のロックが必要になるため、ページレベルロックまたはテーブルロックよりも処理速度が低下する。

  • データの大部分で GROUP BY を頻繁に実行するか、テーブル全体を頻繁にスキャンする必要がある場合、他のロックよりも明らかに効率が悪化する。

  • 高いロックレベルを使用すると、タイプの異なるロックをサポートし、行レベルロックの場合と同様にロックオーバーヘッドが減少するようにアプリケーションを調整するのも容易である。

以下の場合、ページレベル/行レベルロックよりもテーブルロックの方が適しています。

  • 大部分が読み込み

  • 厳密なキーでの読み込みおよび更新。この場合、1 つのキー読み込みで取得できる 1 つのレコードを更新または削除する。

    UPDATE table_name SET column=value WHERE unique_key#
    DELETE FROM table_name WHERE unique_key=#
    

  • SELECTINSERT(ならびに少数の UPDATE および DELETE ステートメント)を組み合わせる。

  • 多数のスキャンまたは GROUP BY をテーブル全体で実行する(書き込みなし)。

行レベル/ページレベルロック以外の他のオプション:

バージョン管理(MySQL では並列 INSERT に使用)。多数の読み取りと同時に単一の書き込みが可能です。つまり、データベース/テーブルでは、ユーザがアクセスを開始した時期に基づき、異なるビューが同じデータに関してサポートされます。これはタイムトラベルにたとえることも、書き込み時コピー、コピーオンデマンドと呼ぶこともできます。

多くの場合、コピーオンデマンドは、ページレベルまたは行レベルのロックよりもはるかに優れています。ただし、最悪の場合、通常のロックよりもはるかに大量のメモリを消費します。

行レベルロックの代わりに、アプリケーションレベルロック(MySQL での get_lock/release_lock と同様)を使用することができます。言うまでもなく、このロックが役立つのは正常に動作するアプリケーションに限られます。

多くの場合、アプリケーションに最適なロックタイプは経験に基づき推測できます。しかし、指定されたロックタイプが別のロックタイプよりも好ましいと判断するのは一般的に極めて困難です。すべてがアプリケーションに依存しており、アプリケーションにおける異なった部分には異なったロックタイプが必要とされるからです。

MySQL でのロックに関するヒントを以下に示します。

多くの Web アプリケーションでは、多くの選択、一部の削除、更新が主としてキーで実行され、挿入が特定のテーブルに対して実行されます。 MySQL の基本設定は、上記に適した状態になっています。

同一テーブル内のレコードを大量に確認する必要のある更新と選択を併用しない場合、同時ユーザは問題になりません。

同一テーブルで挿入と削除を併用する場合、INSERT DELAYED が役立つことがあります。

また、LOCK TABLES を使用して処理速度を向上させることもできます(単一ロックでの多数の更新は、ロックなしの更新よりもはるかに高速です)。複数のテーブルに分割するのも有効な対策です。

MySQL でのテーブルロックに処理速度の問題がある場合、テーブルの一部をInnoDB または BDB テーブルに変換して解決できることもあります。 See 項7.5. 「InnoDB テーブル」。 See 項7.6. 「BDB または BerkeleyDB テーブル」

このマニュアルの最適化に関するセクションでは、アプリケーションの調整方法の多種多様な局面について取り上げています。 See 項5.2.13. 「その他の最適化のヒント」

E.5. RTS スレッドに関するコメント

RTS スレッドパッケージと MySQL の併用を試みたところ、以下の問題が発生しました。

これらのパッケージでは、多数の POSIX 呼び出しが使用されるほか、すべての関数のラッパを作成するのに非常に時間がかかります。そこで、スレッドライブラリを最新の POSIX 仕様に変更した方が簡単なのではないかと考えるようになりました。

一部のラッパは作成済みです。詳細については、mysys/my_pthread.c を参照してください。

少なくとも以下を変更する必要があります。

pthread_get_specific では 1 つの引数が使用されます。 sigwait では 2 つの引数が使用されます。 多くの関数(少なくとも pthread_cond_waitpthread_cond_timedwait) からエラー時にエラーコードが返される必要があります。ここでは -1 が返され、errno が設定されます。

もう 1 つの問題は、ユーザレベルのスレッドによって ALRM シグナルが使用され、そのために多くの関数(readwriteopen...)が中断されることです。 MySQL では、中断されたすべての関数における割り込みに対して再試行する必要がありますが、確認するのは容易ではありません。

解決されていない最大の問題は以下のとおりです。

スレッドレベルのアラームを取得するため、mysys/thr_alarm.c を変更し、pthread_cond_timedwait() でアラームとアラームの間に待機しましたが、エラー EINTR で中断されました。原因を調べるためにスレッドライブラリのデバッグを試みたものの、簡単な解決策は見つかりませんでした。

MySQL と RTS スレッドの併用を試みる場合、以下を行うことをお奨めします。

  • MySQL で使用される関数をスレッドライブラリから POSIX に変更する。 変更するのに時間はかからない。

  • -DHAVE_rts_threads ですべてのライブラリをコンパイルする。

  • thr_alarm をコンパイルする。

  • 実装に若干の差異がある場合、my_pthread.hmy_pthread.c の変更により修正することができる。

  • thr_alarm を実行する。実行時に ``警告''、``エラー''、中断メッセージのいずれも表示されなかった場合、正常に実行されています。Solaris で正常に実行された場合の例を以下に示します。

    Main thread: 1
    Thread 0 (5) started
    Thread: 5  Waiting
    process_alarm
    Thread 1 (6) started
    Thread: 6  Waiting
    process_alarm
    process_alarm
    thread_alarm
    Thread: 6  Slept for 1 (1) sec
    Thread: 6  Waiting
    process_alarm
    process_alarm
    thread_alarm
    Thread: 6  Slept for 2 (2) sec
    Thread: 6  Simulation of no alarm needed
    Thread: 6  Slept for 0 (3) sec
    Thread: 6  Waiting
    process_alarm
    process_alarm
    thread_alarm
    Thread: 6  Slept for 4 (4) sec
    Thread: 6  Waiting
    process_alarm
    thread_alarm
    Thread: 5  Slept for 10 (10) sec
    Thread: 5  Waiting
    process_alarm
    process_alarm
    thread_alarm
    Thread: 6  Slept for 5 (5) sec
    Thread: 6  Waiting
    process_alarm
    process_alarm
    
    ...
    thread_alarm
    Thread: 5  Slept for 0 (1) sec
    end
    

E.6. 異なったスレッドパッケージ間の差異

MySQL は、使用されるスレッドパッケージによって大きく左右されます。そのため、MySQL に適したプラットフォームを選択する場合、スレッドパッケージは極めて重要です。

スレッドパッケージには、少なくとも以下の 3 種類があります。

  • 単一プロセス内のユーザスレッド。スレッドの切り替えはアラームによって管理され、スレッドライブラリがすべての非スレッドセーフ関数をロックによって管理する。実行中のスレッドがデータを待機しなければならない場合、読み取り、書き込み、選択などの操作は通常、別のスレッドに切り替えるスレッド固有の select で管理される。ユーザスレッドパッケージが標準ライブラリ(古いバージョンの FreeBSD および BSDI スレッド)に統合されている場合、そのパッケージに必要なオーバーヘッドは、すべての安全でない呼び出し(MIT-pthread、FSU Pthread、RTS thread)にマッピングしなければならないスレッドパッケージよりも少なくて済む。一部の環境(たとえば SCO)では、すべてのシステムコールがスレッドセーフなので、マッピングは非常に容易である(SCO における FSU Pthread)。欠点:マッピングされたすべての呼び出しに必要な時間はごくわずかであり、あらゆる状況に対処するのが極めて難しい。通常、スレッドパッケージによって処理されないシステムコールもいくつか存在する(MIT-pthread、ソケットなど)。スレッドのスケジュールは常に最適とは限らない。

  • 個別プロセス内のユーザスレッド。スレッド切り替えはカーネルによって行われ、すべてのデータはスレッド間で共有される。スレッドパッケージは、スレッド間でデータが共有されるように標準スレッド呼び出しを管理する。この方法は LinuxThread で使用されている。欠点:プロセスが大量。スレッド作成が遅い。1 つのスレッドがクラッシュした場合、通常は残りのスレッドがハングしているので、それらをすべて強制終了した後に再起動しなければならない。スレッド切り替えには若干のコストがかかる。

  • カーネルスレッド。スレッド切り替えは、スレッドライブラリまたはカーネルによって行われ、極めて高速である。すべて 1 つのプロセスで処理されるが、一部のシステムでは ps によって異なったスレッドが表示されることがある。1 つのスレッドが中止されると、プロセス全体が中止される。多くのシステムはスレッドセーフであり、必要とされるオーバーヘッドはごくわずかである。Solaris、HP-UX、AIX、OSF/1 にはカーネルスレッドがある。

一部のシステムでは、システムライブラリ内のユーザレベルスレッドによってカーネルスレッドが管理される。そのような場合、スレッド切り替えはスレッドライブラリによってのみ可能であり、カーネルは実際には ``スレッド対応'' ではない。


This is a translation of the MySQL Reference Manual that can be found at dev.mysql.com. The original Reference Manual is in English, and this translation is not necessarily as up to date as the English version.

アダルトレンタルサーバー