目次
Access denied
エラーMySQL server has gone away
エラーCan't connect to [local] MySQL server
エラーClient does not support authentication protocol
エラーHost '...' is blocked
エラーToo many connections
エラーSome non-transactional changed tables couldn't be rolled
back
エラーOut of memory
エラーPacket too large
エラーThe table is full
エラーCan't create/write to file
エラーCommands out of sync
エラーIgnoring user
エラーTable 'xxx' doesn't exist
エラーCan't initialize character set xxx
エラーこの章では、ユーザが遭遇するいくつかの一般的な問題とエラーメッセージについて説明しています。どんな問題か見分ける方法と、問題を解決するために行わなければならないことがわかります。また、一般的な問題の適切な解決方法についても記載されています。
問題に遭遇した場合、まず、問題の原因となっているプログラムまたは装置を突き止めます。
以下の症状がある場合は、ハードウェア(メモリ、マザーボード、CPU、ハードディスク)の問題かカーネルの問題である可能性あり。
キーボードが動作しない。これは通常、CapsLock キーを押すことで確認できる。CapsLock ライトが変わらない場合は、キーボードを取り替える必要がある(これを行う前に、コンピュータを再起動し、キーボードに接続されているすべてのケーブルを確認する)。
マウスポインタが動かない。
マシンがリモートマシンの ping に応答しない。
複数の無関係のプログラムが正しく動作しない。
システムが予期せず再起動した場合(誤ったユーザレベルのプログラムは、決してシステムを停止できない)。
この場合、まずケーブルをすべて確認し、その後いくつかの診断ツールを実行してハードウェアを確認する。 また、問題が解決される可能性のある、使用しているオペレーティングシステム用の修正プログラム、アップデート、または Service Pack があるかどうかを確認する。 すべてのライブラリ(glibc など)が最新であることも確認する。
メモリ問題を早期に検出するためには ECC メモリ内蔵のマシンが有効である。
キーボードがロックされている場合、別のユーザからマシンにログインし、kbd_mode
-a
を実行してロックを解除できる場合がある。
問題の原因を突き止めるためには、システムログファイル(/var/log/messages など)を調べる。問題が MySQL にあると考えられる場合は、MySQL のログファイルも調べる必要がある。 See 項4.10.4. 「バイナリログ」。
ハードウェアの問題ではないと考えられる場合には、問題の原因となるプログラムを突き止める必要がある。
top
、ps
、taskmanager
や同様のプログラムを使用して、すべての CPU
を占有してしまっているプログラムや、マシンをロックしているプログラムを調べる。
top
、df
や同様のプログラムを使用して、メモリ、ディスク領域、開いているファイルや他の重要なリソースが不足しているかどうかを確認する。
暴走プロセスが問題となっている場合は、まずその強制終了を試みる。強制終了されない場合は、オペレーティングシステムにバグがある可能性がある。
他の可能性をすべて調査し、問題の原因となっているのが MySQL サーバか MySQL クライアントであると結論づいた場合には、弊社メーリングリストまたはサポートチームにバグレポートをお送りください。バグレポートには、システムの動作、および発生していると考えられることを、詳細に記載してください。また、問題の原因が MySQL であると考えられる理由についても記入してください。この章のすべての状況を考慮に入れてください。システムを調査したときに、問題がどのように発生したかを正確に記入してください。プログラムまたはログファイルの出力またはエラーメッセージを記入する場合は、'カット & ペースト' を使用してください。
動作していないプログラムおよびすべての症状を詳細に記述するようにしてください。過去、"システムが動作しない" としか記述されていないバグレポートを多く受け取りました。これでは、何が問題なのかわかりません。
プログラムが失敗する場合は、以下を確認すると役立ちます。
そのプログラムがセグメンテーションフォルトしてコアダンプを作成しているか。
プログラムが CPU
を占有しているか。top
でチェックする。何か重い処理を行っている可能性があるため、プログラムをしばらく動作させる。
問題の原因が mysqld
サーバである場合は、mysqladmin -u root
ping
または mysqladmin -u root
processlist
を実行できるか。
MySQL
サーバに接続しようとすると、クライアントプログラムにどのようなメッセージが表示されるか(たとえば、mysql
で試す)。
クライアントが動かなくなるか。プログラムから何か出力があるか。
バグレポートをお送りいただく際には、このマニュアルに記載されている原則に従ってください。 See 項1.7.1.2. 「質問またはバグの報告」。
Access denied
エラーMySQL server has gone away
エラーCan't connect to [local] MySQL server
エラーClient does not support authentication protocol
エラーHost '...' is blocked
エラーToo many connections
エラーSome non-transactional changed tables couldn't be rolled
back
エラーOut of memory
エラーPacket too large
エラーThe table is full
エラーCan't create/write to file
エラーCommands out of sync
エラーIgnoring user
エラーTable 'xxx' doesn't exist
エラーCan't initialize character set xxx
エラーこのセクションでは、頻繁に発生するいくつかのエラーについて説明します。エラーの内容と問題の解決方法を説明します。
このセクションでは、関連する Lost
connection to server during query
エラーもカバーしています。
MySQL server has gone away
エラーの最も一般的な原因は、サーバがタイムアウトして接続がクローズしたことです。デフォルトでは、何も起きない状態が
8
時間続くと、サーバは接続をクローズします。この時間は、mysqld
開始時に wait_timeout
変数を設定することで変更できます。
MySQL server has gone away
エラーが発生する一般的なもう一つの原因としては、MySQL
とのコネクション上で ``close''
を発行し、クローズしたコネクションでクエリを実行しようとしたことが考えられます。
スクリプトがある場合は、クライアントが自動再接続を実行するためのクエリを再発行するだけで解決します。
この場合、通常以下のエラーコードが取得されます(OS 依存です)。
エラーコード | 説明 |
CR_SERVER_GONE_ERROR | クライアントがサーバに問い合わせを送信できませんでした。 |
CR_SERVER_LOST | クライアントがサーバに書き込みを行った際エラーは発生しませんでしたが、問い合わせに対して完全な回答(または何らかの回答)が返ってきませんでした。 |
誰かが kill #スレッドID#
で実行中のスレッドを強制終了した場合も、このエラーが発生します。
mysqladmin version
を実行し、使用可能時間を調べることによって、MySQL
が強制終了されていないことを確認できます。問題が
mysqld
のクラッシュであれば、クラッシュの理由を見つけ出すことに注力してください。
この場合、まずクエリを再発行して、MySQL
が再び強制終了されるかどうかをチェックする必要があります。
See 項A.4.1. 「MySQL が何度もクラッシュする場合に行うこと」。
間違ったクエリか大きすぎるクエリをサーバに送信した場合も、このエラーが発生する可能性があります。mysqld
は大きすぎるか異常のあるパケットを取得すると、クライアントに何か問題が発生したとみなし、接続をクローズします。大きなクエリが必要な場合(たとえば、大きな
BLOB
カラムを使用している場合)、mysqld
を -O max_allowed_packet=#
オプション(デフォルト
1MB)で起動して、クエリ制限を引き上げることができます。拡張メモリは要求に応じて割り当てられます。そのため、mysqld
は、ユーザが大きなクエリを発行するときや、mysqld
が大きな結果レコードを返す必要のあるときだけ、メモリを増やして割り当てます。
クライアントが 4.0.8 より古く、サーバが 4.0.8 以上の場合、またはその逆の場合、16MB 以上のパケットを送信すると接続が失われます。
この問題についてバグレポートを作成する際には、必ず以下の情報を記入してください。
MySQL
が強制終了されたかどうか(この情報は、hostname.err
ファイル
にある)。 See
項A.4.1. 「MySQL が何度もクラッシュする場合に行うこと」。
特定のクエリが、mysqld
と、クエリ実行前に CHECK TABLE
によるチェックが実行された関連テーブルを強制終了する場合、このテストケースを実行することができるか。
See 項E.1.6. 「テーブルが破損した場合にテストケースを作成する」。
MySQL サーバにおける wait_timeout
変数の値は何か。 この値は、mysqladmin
variables
で確認することができる。
mysqld
を --log
で実行し、発行したクエリがログに出力されているかどうかチェックしたか。
Unix上の MySQL は mysqld
サーバに次の2つの方法で接続することができます。Unix
ソケット、これはファイルシステム上のファイル(デフォルトでは
/tmp/mysqld.sock
)を通して接続します。または
TCP/IPで、これはポート番号を通して接続します。
Unix ソケットは、TCP/IP
より高速ですが、同じコンピュータのサーバに接続する場合にしか使用できません。Unix
ソケットは、ホスト名を指定しない場合、または特別なホスト名
localhost
を指定する場合に使用されます。
Windows では、mysqld
サーバが 9x/Me
で動作している場合、TCP/IP
を介してのみ接続できます。サーバが NT/2000/XP
で動作しており、mysqld が
--enable-named-pipe
で起動している場合は、名前付きパイプと接続することもできます。名前付きパイプの名前は
MySQL です。 mysqld
に接続する際にホスト名を与えない場合は、MySQL
クライアントは最初に名前付きパイプに接続しようとします。これが正しく機能しない場合は、TCP/IP
ポートに接続します。ホスト名として
.
を使用することにより、Windows
の名前付きパイプを強制的に使用できます。
エラー(2002)Can't connect to ...
は、通常、MySQL
サーバがシステム上で動作していないか、間違ったソケットファイルや
TCP/IP ポートを使用して、mysqld
サーバに接続しようとした場合に発生します。
サーバ上で mysqld
というプロセスが動作しているかどうか、(ps
か、Windows
の場合はタスクマネージャを使用して)最初に確認してください。mysqld
プロセスがなければ、これを起動してください。
See 項2.4.2. 「MySQL サーバの起動に関する問題」。
mysqld
プロセスが動作している場合は、さまざまな接続を試してサーバを確認できます(ポート番号とソケットのパス名は、当然セットアップ時と異なる可能性があります)。
shell>mysqladmin version
shell>mysqladmin variables
shell>mysqladmin -h `hostname` version variables
shell>mysqladmin -h `hostname` --port=3306 version
shell>mysqladmin -h 'ip for your host' version
shell>mysqladmin --protocol=socket --socket=/tmp/mysql.sock version
hostname
コマンドは、フォワードクォートではなくバッククォートで囲んでください。これによって、hostname
の出力(つまり現在のホスト名)が
mysqladmin
コマンドに代入されます。
Can't connect to local MySQL server
エラーが発生する理由として、以下のことが考えられます。
mysqld
が動作していない。
MIT-pthreads
を使用するシステム上で実行している。
ネイティブスレッドを持たないシステムで実行している場合、mysqld
は MIT-pthreads パッケージを使用する。See
項2.2.3. 「MySQL がサポートしているオペレーティングシステム」。ただし、すべてのMIT-pthreads
バージョンが Unix
ソケットをサポートしているわけではない。ソケットサポートのないシステムでは、サーバに接続する際に、常にホスト名を明示的に指定する必要がある。以下のコマンドを使用して、サーバへの接続を確認する。
shell> mysqladmin -h `hostname` version
誰かが、mysqld
が使用する Unix
ソケット(デフォルトでは
/tmp/mysqld.sock
)を削除した。MySQL
ソケットを削除する cron
ジョブ(たとえば、/tmp
ディレクトリから古いファイルを削除するジョブ)を行っている可能性がある。mysqladmin
version
を実行し、mysqladmin
が使用するソケットが本当に存在するかどうかを常にチェックすることができる。この場合の修正方法は、mysqld.sock
を削除しないように cron
ジョブを変更するか、ソケットを別の場所に移動させることである。
See 項A.4.5. 「MySQL ソケットファイル /tmp/mysql.sock
の保護または変更方法」。
--socket=/path/to/socket
オプションを指定して、mysqld
サーバを開始した。サーバのソケットパス名を変更する場合は、MySQL
クライアントに新しいパスを通知する必要がある。パスを通知するには、ソケットパスを引数としてクライアントに提供する。
See 項A.4.5. 「MySQL ソケットファイル /tmp/mysql.sock
の保護または変更方法」。
Linux を使用中にスレッドが 1
つ消滅した(コアダンプした)。この場合、(たとえば、新しい
MySQL サーバを実行する前に
mysql_zap
スクリプトを使用して)他の
mysqld
スレッドを強制終了する必要がある。 See
項A.4.1. 「MySQL が何度もクラッシュする場合に行うこと」。
ソケットファイルを保持しているディレクトリ、またはソケットファイル自体への読み取り権限と書き込み権限がない可能性がある。この場合、アクセス可能なディレクトリを使用するように、ディレクトリまたはファイルに対する権限を変更するか、mysqld
を再起動する必要がある。
エラーメッセージ Can't connect to MySQL server
on some_hostname
が発生した場合は、以下を行って問題を突き止めることができます。
telnet your-host-name tcp-ip-port-number
を実行してサーバが立ち上がっているかどうかを確認し、Enter
キーを数回押す。このポートで MySQL
サーバが動作している場合は、動作中の MySQL
サーバのバージョン番号を含むレスポンスが返ってくる。telnet:
Unable to connect to remote host: Connection
refused
などのエラーが発生する場合は、サーバは所定のポートで動作していない。
ローカルマシンの mysqld
デーモンに接続し、mysqladmin
variables
で mysqld
が使用するように設定された TCP/IP
ポート(変数
port
)を確認する。
mysqld
サーバが、--skip-networking
オプションで起動されていないか確認する。
MySQL 4.1 では、パスワードハッシュアルゴリズムに基づく認証プロトコルが使用されていますが、これは旧クライアントが使用しているものと互換性がありません。 サーバを 4.1 にアップグレードすると、旧クライアントで接続しようとした場合に、以下のエラーメッセージが発生する可能性があります。
shell> mysql
Client does not support authentication protocol requested
by server; consider upgrading MySQL client
この問題を解決するには、以下のいずれかを行ってください。
全クライアントプログラムをアップグレードして、4.1.1 以降のクライアントライブラリを使用するようにする。
4.1 より前のクライアントから接続する場合は、旧パスワードでユーザアカウントを使用する。
4.1 より前のクライアントを必要とするユーザをリセットし、旧パスワードを使用するようにする。
mysql>UPDATE user SET Password = OLD_PASSWORD('mypass')
->WHERE Host = 'some_host' AND User = 'some_user';
mysql>FLUSH PRIVILEGES;
サーバが旧パスワードハッシュアルゴリズムを使用するように指定する。
--old-passwords
を指定して mysqld
を開始する。
ロングパスワードを持っているユーザすべてのパスワードを設定する。これらのユーザは、以下で調べることができる。
SELECT * FROM mysql.user WHERE LEN(password) > 16;
パスワードハッシュと認証の背景については、項4.3.11. 「MySQL 4.1 のパスワードハッシュ」 を参照してください。
以下のエラーが発生した場合
Host 'hostname' is blocked because of many connection errors. Unblock with 'mysqladmin flush-hosts'
これは、mysqld
が
'hostname'
ホストから多くの接続エラー(max_connect_errors
)を受けた場合に発生します。max_connect_errors
大量発生後、mysqld
は何か問題(クラッカーからの攻撃など)が発生したと判断し、このホストからの接続を拒否するようにします。これを解除するには、mysqladmin
flush-hosts
コマンドを実行します。
デフォルトでは、接続エラーが 10
回発生すると、mysqld
はそのホストを拒否します。
この値は、以下のようにサーバを開始することで簡単に変更できます。
shell> mysqld_safe -O max_connect_errors=10000 &
特定のホストに対してこのエラーメッセージが発生する場合は、まず、そのホストからの
TCP/IP
接続に問題がないか確認してください。TCP/IP
接続が機能していない場合は、max_connect_errors
変数の値を増やしても効果はありません。
MySQL に接続しようとして Too many
connections
エラーが発生する場合は、すでに
mysqld
サーバに接続している
max_connections
クライアントが存在しています。
デフォルト(100)より多い接続を行う場合は、max_connections
変数の値を 100
より大きくして、mysqld
を再起動する必要があります。
実際は、mysqld
では(max_connections
+1)クライアントの接続が許可されています。最後の接続は、SUPER
特権のあるユーザ用に予約されています。一般ユーザにこの特権を与えないことによって(一般ユーザにこの特権は必要ありません)、この特権のある管理者はログインして、SHOW
PROCESSLIST
を使用して問題を見つけることができます。 See
項4.6.8.6. 「SHOW PROCESSLIST
」。
MySQL 接続の最大数は、スレッドライブラリが特定のプラットフォームでどの程度まで有用であるかに依存します。Linux または Solaris では、使用している RAM のサイズと、クライアントが何を実行しているかによって、500 ? 1000 の同時接続をサポートできます。
ROLLBACK
を実行しようとしたときに
Warning: Some non-transactional changed tables couldn't
be rolled back
が発生した場合、トランザクションで使用したテーブルの中にトランザクションをサポートしていないものがあることを示しています。これら非トランザクションテーブルは、ROLLBACK
ステートメントからの影響を受けません。
最も一般的には、このエラーが発生するのは、mysqld
バイナリでサポートされていない型のテーブルを作成しようとしたときです。
mysqld
がテーブル型をサポートしていない場合(またはスタートアップオプションでテーブル型が無効化されている場合)、代わりに、要求したものと最も類似したテーブル型(おそらく
MyISAM
)が作成されます。
以下のコマンドでテーブルのテーブル型を確認できます。
SHOW TABLE STATUS LIKE 'table_name'
。 See
項4.6.8.2. 「SHOW TABLE STATUS
」。
以下のコマンドで mysqld
バイナリがサポートする拡張子を確認できます。
SHOW VARIABLES LIKE 'have_%'
。 See
項4.6.8.4. 「SHOW VARIABLES
」。
クエリを発行し、以下のようなエラーが発生した場合
mysql: Out of memory at line 42, 'malloc.c' mysql: needed 8136 byte (8k), memory in use: 12481367 bytes (12189k) ERROR 2008: MySQL client ran out of memory
エラーが MySQL クライアント mysql
を参照していることに注意してください。このエラーの原因は、クライアントにすべての結果を格納するだけのメモリがないことです。
問題を解決するには、まず、クエリが正しいことを確認してください。そのクエリは大量のレコードを返すものでしょうか
? そうであれば、mysql --quick
を使用できます。これは、結果セットを取り出すために
mysql_use_result()
を使用します。これによってクライアントの負荷が小さくなります(サーバ側では負荷が大きくなります)。
MySQL クライアントまたは mysqld
サーバが max_allowed_packet
バイトより大きいパケットを受け取った場合、Packet
too large
エラーが発生し、接続がクローズされます。
MySQL 3.23 で使用できる最も大きなパケットは 16M です(クライアントおよびサーバプロトコルの制限によります)。MySQL 4.01 以上では、パケットの大きさは、サーバ上のメモリ容量でのみ制限されます(理論上は最大 2G)。
1 つの通信パケットは、MySQL サーバに送信される単一の SQL ステートメントか、クライアントに送信される単一行です。
MySQL クライアントまたは mysqld
サーバが max_allowed_packet
バイトより大きいパケットを受け取った場合は、Packet
too
large
エラーが発生し、接続がクローズされます。クライアントの中には、通信パケットが大きすぎると
Lost connection to MySQL server during query
エラーを発生するものもあります。
クライアントとサーバには、共に独自の
max_allowed_packet
変数があります。大きなパケットを扱う場合は、クライアントとサーバ両方の変数を増やす必要があります。
メモリは必要な場合にのみ割り当てられるため、この変数を増やしても安全です。この変数は、クライアントとサーバ間の不正なパケットを捕捉したり、メモリ不足になってしまうような大きなパケットを誤って使用したりしないための予防策です。
mysql
クライアントを使用している場合は、クライアントを
mysql --set-variable=max_allowed_packet=8M
で開始することで、より大きなバッファを指定することができます。
他のクライアントには、この変数を設定する別の方法があります。
MySQL 4.0 以降、--set-variable
は使用されなくなっています。代わりに
--max-allowed-packet=8M
を使用してください。
オプション設定ファイルを使用すると、mysqld
で max_allowed_packet
をより大きなサイズに設定することができます。たとえば、MEDIUMBLOB
の許容範囲いっぱいのデータをテーブルに入れる場合、--set-variable=max_allowed_packet=16M
オプションを指定してサーバを起動します。
大きな BLOB
を使用している場合、大きなパケットに関する見慣れない問題が発生する可能性がありますが、これは、mysqld
に、そのクエリを処理できるだけの十分なメモリへのアクセス権がないことが原因です。その場合は、mysqld_safe
スクリプトの始めに ulimit -d 256000
を追加して、mysqld
を再起動してください。
MySQL 3.23.40
から、mysqld
を
--warnings
で開始した場合のみ、Aborted
connection
エラーが発生します。
エラーログに以下のようなエラーが含まれている場合は、
010301 14:38:23 Aborted connection 854 to db: 'users' user: 'josh'
See 項4.10.1. 「エラーログ」。
以下が発生したと考えられます。
クライアントプログラムが終了前に
mysql_close()
を呼び出さなかった。
クライアントが何の要求もせずに、wait_timeout
または interactive_timeout
より多くの時間スリープ状態であった。 See
項4.6.8.4. 「SHOW VARIABLES
」。
クライアントプログラムが、転送中に突然終了した。
上記のことが発生した場合、サーバ変数
Aborted_clients
の値が増えます。
以下の場合、サーバ変数
Aborted_connects
の値が増えます。
接続パケットに正しい情報が含まれていない場合
ユーザにデータベースに接続する権限がない場合
ユーザが間違ったパスワードを使用した場合
接続パケットの取得に、connect_timeout
で指定されている秒数より多く要した場合
See 項4.6.8.4. 「SHOW VARIABLES
」。
上記のことは、不正ユーザがデータベースに侵入しようとしている可能性を示しています。
中止されたクライアントおよび中止された接続エラーのその他の原因
Linux での Ethernet プロトコルの使用(半二重と全二重)。 多くの Linux Ethernet ドライバには、このバグがある。2つのマシン間で ftp を使用して大きなファイルを転送し、このバグについてテストする必要がある。 転送が burst-pause-burst-pause ... モードで行われている場合は、Linux 二重シンドロームに陥っている。 唯一の解決策は、ネットワークカードとハブ/スイッチの二重モードを、全二重または半二重に切り替え、その結果をテストし最も良い設定を行うことである。
読み取りの中断の原因になるスレッドライブラリの問題。
TCP/IP の設定間違い。
不良 Ethernet、ハブ、スイッチ、ケーブルなど。これは、ハードウェアを交換してみることでしか正しく診断できない。
max_allowed_packet
が小さすぎるか、クエリが
mysqld
に割り当てられたメモリより多くのメモリを必要としている。
See 項A.2.9. 「Packet too large
エラー」。
このエラーが発生するケースとしては、以下のようなさまざまなケースが考えられます。
旧バージョン(3.23.0 より前)の MySQL
を使用していて、メモリ内のテンポラリテーブルが
tmp_table_size
バイトより大きくなったとき。
この問題を回避するには、-O
tmp_table_size=#
オプションを使用して
mysqld
でテンポラリテーブルサイズを大きくするか、問題のクエリを発行する前に、SQL
オプション SQL_BIG_TABLES
を使用する。 See 項5.5.6. 「SET
構文」。
また、--big-tables
オプションを指定して mysqld
を開始することもできる。
これは、すべてのクエリに
SQL_BIG_TABLES
を使用しているのとまったく同じ。
MySQL バージョン 3.23
では、メモリ内のテンポラリテーブルが
tmp_table_size
より大きくなると、サーバがそのテーブルを自動的にディスクベースの
MyISAM
テーブルに変換した。
InnoDB
テーブルを使用しており、InnoDB
のテーブルスペースが不足している。この問題を解決するには、InnoDB
のテーブルスペースを拡張する。
サイズが 2GB
のファイルしかサポートしていない OS で
ISAM
または MyISAM
テーブルを使用しており、データファイルまたはインデックスファイルが制限に達した。
MyISAM
テーブルを使用しており、必要なデータまたはインデックスサイズが、MySQL
がポインタを割り当てたものより大きくなっている(MAX_ROWS
を CREATE TABLE
に指定しない場合は、MySQL は 4G
のデータを保持できる分だけポインタを割り当てる)。
最大データとインデックスサイズを確認できる。確認するには、以下のコマンドを実行するか、
SHOW TABLE STATUS FROM database LIKE 'table_name';
myisamchk -dv database/table_name
を使用する。
これで問題がある場合は、以下の方法で解決できる。
ALTER TABLE table_name MAX_ROWS=1000000000 AVG_ROW_LENGTH=nnn;
この場合、MySQL
はレコード数だけに基づいて必要なスペースを最適化することができないので、BLOB/TEXT
フィールドをもつテーブルに
AVG_ROW_LENGTH
を指定することが必要になる。
以下のようなクエリのエラーが発生する場合
Can't create/write to file '\\sqla3fe_0.ism'.
MySQL
が、特定のテンポラリディレクトリに結果セット用のテンポラリファイルを作成できないことを示しています(上記のエラーは、Windows
での典型的なエラーメッセージですが、Unix
でのエラーメッセージもよく似たメッセージになります)。
解決するには、--tmpdir=path
を指定して mysqld
を起動するか、オプション設定ファイルに以下のコードを追加します。
[mysqld] tmpdir=C:/temp
c:\\temp
ディレクトリが存在していると仮定しています。
See 項4.1.2. 「my.cnf
オプション設定ファイル」。
また perror
で、取得するエラーコードを確認します。1つの原因としてディスクがいっぱいになっていることも考えられます。
shell> perror 28
Error code 28: No space left on device
クライアントコードの中に Commands out of
sync; you can't run this command now
がある場合は、間違った順序でクライアント関数を呼び出しています。
たとえば、mysql_free_result()
を呼び出す前に mysql_use_result()
を使って新しいクエリを実行しようとすると、上記のことが起こる可能性があります。
また、データを返す 2つのクエリを、その間に
mysql_use_result()
や
mysql_store_result()
を呼び出さないで実行した場合にも起こる可能性があります。
次のエラーが発生する場合
Found wrong password for user: 'some_user@some_host';
ignoring user
mysqld
が再起動されたとき、またはアクセス権テーブルが再ロードされたときに、user
テーブルに無効なパスワードのエントリが見つかったことを示しています。結果として、このエントリはアクセス権システムから無視されます。
この問題の考えられる原因と修正方法
旧 user
テーブルで新バージョンの
mysqld
を実行している可能性がある。
mysqlshow mysql user
を実行し、パスワードフィールドが 16
文字より短いかどうかを調べることによって、このことを確認できる。短い場合、scripts/add_long_password
スクリプトを実行して、この状態を修正できる。
ユーザのパスワードは旧パスワード(8
文字長)であるが、mysqld
が
--old-protocol
オプションで開始されなかった。
user
テーブルのユーザを新規パスワードで更新するか、mysqld
を --old-protocol
を指定して再起動する。
PASSWORD()
関数を使用せずに、user
テーブルにパスワードを指定した。mysql
を使用して user
テーブルのユーザを新規パスワードで更新する。このとき、必ず
PASSWORD()
関数を使用すること。
mysql>UPDATE user SET password=PASSWORD('your password')
->WHERE user='XXX';
エラー Table 'xxx' doesn't exist
または
Can't find file: 'xxx' (errno: 2)
が発生する場合、xxx
という名前のカレントデータベースにテーブルがないことを示しています。
MySQL では、データベースとテーブルの格納にディレクトリとファイルを使用するため、データベースとテーブル名は、大文字と小文字の区別がある(ケース依存)ことに注意してください (Windows では、データベースとテーブル名に大文字小文字の区別がありません。しかし、クエリ内の特定テーブルへの参照では大文字と小文字を完全に合わせる必要があります)。
SHOW TABLES
を使用して、カレントデータベースにあるテーブルを確認できます。
See 項4.6.8. 「SHOW
構文」。
以下のエラーが発生した場合
MySQL Connection Failed: Can't initialize character set xxx
以下のことが考えられます。
キャラクタセットがマルチバイトのキャラクタセットであるが、クライアントではキャラクタセットがサポートされていない。
この場合、クライアントを
--with-charset=xxx
または
--with-extra-charsets=xxx
で再コンパイルする。 See
項2.3.3. 「一般的な configure
オプション」。
標準 MySQL バイナリはすべて
--with-extra-character-sets=complex
でコンパイルされている。これによって、マルチバイトのキャラクタセットすべてがサポートされる。
See 項4.7.1. 「データおよびソート用キャラクタセット」。
キャラクタセットが単純なキャラクタセットで、それが
mysqld
に組み込まれておらず、キャラクタセットの定義ファイルがクライアントの予想する場所にない。
この場合、以下のようにする。
キャラクタセットをサポートするように、クライアントを再コンパイルする。
See 項2.3.3. 「一般的な configure
オプション」。
クライアントに、キャラクタセットの定義ファイルの場所を通知する。多くのクライアントに対して、--character-sets-dir=path-to-charset-dir
オプションを使用して通知するできる。
文字定義ファイルを、クライアントがその定義ファイルがあると予想しているパスにコピーする。
MySQL から ERROR '...' not found (errno:
23)
、Can't open file: ... (errno:
24)
、または errno 23
または
errno 24
とともに他のエラーを受け取った場合、MySQL
に十分なファイル記述子が割り当てられていないことを示しています。perror
ユーティリティを使用して、エラー番号が何を意味しているか、その内容を取得することができます。
shell>perror 23
File table overflow shell>perror 24
Too many open files shell>perror 11
Resource temporarily unavailable
ここでの問題は、mysqld
が非常に多くのファイルを同時に開こうとしていることです。mysqld
が同時に多くのファイルを開かないように指定するか、mysqld
で使用できるファイル記述子の数を増やすことができます。
mysqld
で同時に開くファイルを少なくするために、mysqld_safe
に -O table_cache=32
オプション(初期値は
64)を指定して、テーブルキャッシュを小さくすることができます。max_connections
の値を減らすことで、オープンファイル数(初期値は
90)も少なくなります。
mysqld
で使用できるファイル記述子の数を変更するために、mysqld_safe
に --open-files-limit=#
オプション、または mysqld
に
-O open-files-limit=#
オプションを使用することができます。 See
項4.6.8.4. 「SHOW VARIABLES
」。
これを行う最も簡単な方法は、オプション設定ファイルにオプションを追加することです。
See 項4.1.2. 「my.cnf
オプション設定ファイル」。
これをサポートしていない旧バージョンの
mysqld
を使用している場合は、mysqld_safe
スクリプトを編集することができます。スクリプトにはコメントアウトされた
ulimit -n 256
行があります。'#'
文字を削除してこの行のコメントを解除し、数字
256 を変更することができます。これによって、
mysqld
で使用できるファイル記述数も変わります。
ulimit
(および
open-files-limit
)によって、ファイル記述子の数を増やすことができます。しかし、オペレーティングシステムで定められた上限までしか増やせません。また
'ハード' リミットが存在し、ルートとして
mysqld_safe
または
mysqld
を開始した場合に限り上書きすることができます(この場合、--user=...
オプションも使用する必要があります)。各プロセスで利用できるファイル記述子の数の
OS
制限を増やす必要がある場合は、そのオペレーティングシステムのドキュメントを参照してください。
tcsh
シェルを実行している場合は、ulimit
は機能しません。 tcsh
は、現在の制限について問い合わせると、間違った値を返します。この場合、mysqld_safe
を sh
で開始する必要があります。
プログラムをリンクするときに、mysql_
で始まる未参照シンボルに関する以下のようなエラーが発生する場合
/tmp/ccFKsdPa.o: In function `main': /tmp/ccFKsdPa.o(.text+0xb): undefined reference to `mysql_init' /tmp/ccFKsdPa.o(.text+0x31): undefined reference to `mysql_real_connect' /tmp/ccFKsdPa.o(.text+0x57): undefined reference to `mysql_real_connect' /tmp/ccFKsdPa.o(.text+0x69): undefined reference to `mysql_error' /tmp/ccFKsdPa.o(.text+0x9a): undefined reference to `mysql_close'
これは、リンク行の最後に
-Lpath-to-the-mysql-library-lmysqlclient
を追加すると解決できます。
uncompress
または
compress
関数で undefined
reference
エラーが発生する場合は、リンク行の最後に
-lz
を追加して再度実行してください。
システムにあるはずの関数(例:
connect
)に対して undefined
reference
エラーが発生する場合は、該当する関数を man
ページで確認し、そのライブラリをリンク行に追加するかどうか判断してください。
以下のように、システムに存在しない関数で
undefined reference
エラーが発生する場合
mf_format.o(.text+0x201): undefined reference to `__lxstat'
これは、通常、使用しているシステムと 100% 互換でないシステム上でライブラリがコンパイルされていることを示しています。この場合、最新の MySQL ソースディストリビューションをダウンロードし、それを独自にコンパイルしてください。 See 項2.3. 「MySQL ソースディストリビューションのインストール」。
プログラムを実行しようとしているが、mysql_
で始まるエラーか、mysqlclient
ライブラリが見つからない未参照シンボルのエラーが発生する場合は、システムが
libmysqlclient.so
共有ライブラリを見つけられないということを示しています。
これを解決するには、以下のいずれかの方法で、関数が組み込まれている共用ライブラリを検索するように、システムに指示します。
LD_LIBRARY_PATH
環境変数に
libmysqlclient.so
が存在するディレクトリのパスを追加する。
LD_LIBRARY
環境変数に
libmysqlclient.so
が存在するディレクトリのパスを追加する。
libmysqlclient.so
をシステムが検索する場所(たとえば
/lib
)にコピーし、ldconfig
を実行して共有ライブラリ情報を更新する。
この問題を解決するもう
1つの方法として、-static
を使用するか、コードをリンクする前に MySQL
の動的ライブラリを削除して、プログラムを静的にリンクする方法があります。2
番目のケースでは、別のプログラムが動的ライブラリを使用していないことを確認する必要があります。
MySQL サーバ mysqld
は、どんな Unix
ユーザでも開始、実行できます。
mysqld
を Unix ユーザ
user_name
で実行できるように変更するには、以下を行ってください。
サーバが動作している場合は、それを停止します(mysqladmin
shutdown
を使用します)。
データベースのディレクトリとファイルを変更して、その中のファイルを読み込んだり書き込んだりする権限を
user_name
に与えます(場合によっては Unix
root
ユーザとして行う必要があります)。
shell> chown -R user_name /path/to/mysql/datadir
MySQL
データディレクトリ内のディレクトリまたはファイルがシンボリックリンクの場合は、リンクに従い、そのファイルやディレクトリが指しているディレクトリとファイルも変更する必要があります。chown
-R
では、シンボリックリンク先まで変更できません。
サーバを user_name
で開始するか、MySQL バージョン 3.22
以降を使用している場合は、mysqld
をUnix root
ユーザで開始して、--user=user_name
オプションを使用します。mysqld
は、接続を許可する前に、Unix ユーザ
user_name
での実行に切り替わります。
システム起動時にサーバを特定のユーザ名で自動的に開始するには、ユーザ名を指定する
user
行を、/etc/my.cnf
オプション設定ファイルかサーバのデータディレクトリにある
my.cnf
オプション設定ファイルの
[mysqld]
グループに追加します。たとえば、以下のようにします。
[mysqld] user=user_name
この時点で、mysqld
プロセスは Unix
ユーザ user_name
として正常に動作します。ただし、アクセス権テーブルの内容は変わりません。デフォルトでは(アクセス権テーブルのインストールスクリプト
mysql_install_db
の実行直後)、mysql
データベースへのアクセスまたはデータベースの作成や破棄の権限を持つ唯一のユーザは
MySQL ユーザ root
です。これらのアクセス権を変更しなかった場合、そのアクセス権はそのまま保持されます。root
以外の Unix
ユーザとしてログインしている場合も、MySQL
root
ユーザとしてMySQLにアクセスできます。そのために行うことは、-u
root
オプションをクライアントプログラムに指定するだけです。
コマンドラインで -u root
を指定して、root
としてMySQL
にアクセスすることと、Unix root
ユーザ、または実際には別の Unix ユーザとして
MySQL
を実行することとは何の関係もありません。MySQL
のアクセス権とユーザ名は、Unix
ユーザ名とは完全に別のものです。Unix
ユーザ名と唯一関連があるのは、クライアントプログラムを呼び出すときに
-u
オプションを指定しない場合に、クライアントが
MySQL ユーザ名として Unix
ログイン名を使用して接続を試みるということだけです。
Unix
ボックスそのものが保護されていない場合は、少なくとも、アクセステーブルの
MySQL root
ユーザにパスワードを設定しておく必要があります。
そうしなければ、マシンにアカウントのあるユーザは、mysql
-u root db_name
を実行して思い通りのことを行えます。
ファイルアクセス権に問題がある場合、たとえばテーブルを作成する際に
mysql
が以下のエラーメッセージを発行した場合
ERROR: Can't find file: 'path/with/filename.frm' (Errcode: 13)
mysqld
起動時に、環境変数
UMASK
が正しく設定されていなかった可能性があります。umask
初期値は 0660
です。以下のように
mysqld_safe
を実行して、この動作を変更することができます。
shell>UMASK=384 # = 600 in octal
shell>export UMASK
shell>/path/to/mysqld_safe &
デフォルトでは、MySQL はアクセス権タイプ 0700
のデータベースと RAID
ディレクトリを作成します。UMASK_DIR
変数を設定して、この動作を変更することができます。この変数を設定すると、UMASK
と UMASK_DIR
が組み合わされて新しいディレクトリが作成されます。たとえば新しいディレクトリすべてにグループアクセス権を与える場合は、以下を実行します。
shell>UMASK_DIR=504 # = 8進数で 770
shell>export UMASK_DIR
shell>/path/to/mysqld_safe &
MySQL バージョン 3.23.25
以降では、UMASK
と
UMASK_DIR
の値がゼロで始まる場合、MySQL
はその値を8進数と仮定します。
See 付録?F. 環境変数。
MySQL バージョンはすべて、リリース前に多くのプラットフォームでテストされています。これは MySQL にバグがないというわけではありませんが、バグがあったとしても、非常に少なく見つけるのが困難です。何か問題がある場合に、システムをクラッシュさせているものを正確に調査することは、この問題の早期解決に役立ちます。
まず、問題は mysqld
デーモンが死んでいることにあるのか、または問題がクライアントに関係しているのかを判断する必要があります。mysqladmin
version
を実行して、mysqld
サーバが稼動していた時間を確認することができます。mysqld
が死んでいる場合は、ファイル
mysql-data-directory/`hostname`.err
を見ることによりその原因を見つけることができます。
See 項4.10.1. 「エラーログ」。
システムの中には、このファイルに
mysqld
が死んだ際のスタックトレースがあるものがあり、resolve_back_stack
で問題を解決できます。See
項E.1.4. 「スタックトレースの使用」。.err
ファイルに書き込まれている変数値は、常に 100
パーセント正確であるとは限りません。
MySQL
のクラッシュの多くは、インデックスファイルやデータファイルの破壊が原因です。
MySQL は、すべての SQL ステートメントの後で
write()
システムコールを呼び出し、ディスク上のデータを更新します。クライアントには、その後その結果が通知されます(delay_key_write
で実行している場合で、データの書き込みだけの場合にはこの限りではありません)。
つまり、OS
によってフラッシュされていないデータがディスクに確実に書き込まれるため、mysqld
がクラッシュした場合でもデータは安全です。--flush
を指定して mysqld
を開始することによって、各 SQL
コマンド実行後、強制的にすべてをディスクと同期させることができます。
つまり、以下のことがなければ、通常は破壊されたテーブルを得ることはありません。
誰かまたは何かが、更新中に
mysqld
またはマシンを強制終了した。
更新中に mysqld
が死ぬようなバグを見つけた。
テーブルを適切にロックしないで、mysqld 外でデータまたはインデックスフファイルを操作している。
優れたファイルシステムロック(通常、lockd
デーモンによって処理される)をサポートしていないシステム上で、同じデータに対して、多くの
mysqld
サーバを実行しているか、--skip-external-locking
で複数サーバを実行している。
mysqld
を混乱させるような不正なデータを含んだ、破損したインデックスまたはデータファイルがある。
データストレージのコードにバグを発見した。これはおそらくあり得ないことだが、可能性としてはある。この場合、修正されたテーブルのコピーに対して
ALTER TABLE
を使用して、ファイルタイプを別のデータストレージエンジンに変更することができる。
クラッシュの原因を見つけるのは非常に難しいので、まず、他で動作しているものが自分の環境でクラッシュするかどうかを確認してください。以下を試してください。
mysqladmin shutdown
で
mysqld
デーモンを停止し、全テーブルで
myisamchk --silent --force */*.MYI
を実行した後、mysqld
デーモンを再起動する。必ず、クリーンな状態から実行すること。
See 章?4. データベース管理。
mysqld --log
を使用して、ログの情報から、特定のクエリがサーバを終了させるかどうかを判断する。バグの
95%
が特定のクエリに関係している。通常、これは、MySQL
再実行直前のログファイルにある最後のクエリの
1 つである。 See 項4.10.2. 「一般クエリログ」。
クエリを実行する直前にすべてのテーブルを確認しても、クエリの
1 つで MySQL
を何度も強制終了させることができる場合、バグを突き止められているので、バグレポートを発行する必要がある。
See 項1.7.1.3. 「バグまたは問題を報告する方法」。
問題の再現に使用するテストケースを作成する。 See 項E.1.6. 「テーブルが破損した場合にテストケースを作成する」。
組み込まれている mysql-test テストと MySQL
ベンチマークを実行する。See
項13.1.2. 「MySQL テストスイート」。これによって
MySQL
を正確にテストできる。ベンチマークにアプリケーションをシミュレートするコードを追加することもできる。ベンチマークは、ソースディストリビューションまたはバイナリディストリビューションの
bench
ディレクトリか、MySQL
インストールディレクトリの
sql-bench
ディレクトリにある。
fork_test.pl
と
fork2_test.pl
を実行する。
デバッグ用に MySQL
を設定している場合は、何か問題が発生した際に、考えられるエラー情報の収集が非常に容易になる。
configure
に
--with-debug
オプションか
--with-debug=full
オプションを指定して MySQL
を再設定し、その後再コンパイルする。 See
項E.1. 「MySQL サーバのデバッグ」。
デバッグ用に MySQL を設定すると、安全なメモリアロケータが組み込まれ、エラーを見つけることができる。また、何が発生しているかについて、多くの情報が提供される。
オペレーティングシステムの最新のパッチを適用しているかどうか確認する。
mysqld
にオプション
--skip-external-locking
を指定する。システムの中には、lockd
ロックマネージャが適切に動作しないものがある。--skip-external-locking
オプションによって、mysqld
に外部ロックを使用しないように指示することができる(つまり、同じデータで
2 つの mysqld
サーバを実行することができない。myisamchk
を使用する場合は注意が必要だが、テストとしてオプションを使用する場合は有益である)。
mysqld
が動作しているように見えるのに応答がなかった時、mysqladmin
-u root processlist
を実行したか。mysqld
は消滅しているように見えても、消滅していない場合がある。すべての接続が使用中であるか、内部ロック問題の可能性がある。
mysqladmin processlist
は、通常、このような場合であっても接続を行うことができ、現在の接続数やその状況に関して有益な情報を取得できる。
他のクエリを実行中に、別のウィンドウで
mysqladmin -i 5 status
または
mysqladmin -i 5 -r status
を実行し、統計を生成する。
以下を実行してみる。
gdb
から(または別のデバッガで)、mysqld
を起動する。 See
項E.1.3. 「mysqld のデバッグ(gdb 使用)」。
テストスクリプトを実行する。
3つの最下位レベルで、バックトレースとローカル変数を出力する。gdb
では、mysqld
が gdb
内部でクラッシュした場合、以下のコマンドでこの出力を実行できる。
backtrace info local up info local up info local
gdb では、info threads
により、存在しているスレッドを調べ、thread
#
(#
はスレッド
ID)で特定のスレッドにスイッチすることができる。
Perl スクリプトでアプリケーションをシミュレートし、MySQL をクラッシュさせたり不正な動作をさせたりする。
バグレポートを送付する。See 項1.7.1.3. 「バグまたは問題を報告する方法」。詳細なレポートにすること。MySQL は多くの人が使用しているため、クラッシュがあなたのコンピュータだけにある何らかの原因に起因している可能性がある(たとえば、特定のシステムライブラリに関連するエラー)。
可変長レコードを持つテーブルに問題があり、BLOB/TEXT
カラム(BLOB/TEXT
カラムのみ)を使用していない場合、ALTER
TABLE
で VARCHAR
すべてを
CHAR
に変更することができる。これによって、MySQL
は固定サイズのレコードを使用する。
固定サイズのレコードは余分な領域を少し取るだけだが、破壊に対して非常に大きな耐性がある。
現在の可変長レコードのコードは、少なくとも 3 年間は何の問題もなく MySQL AB で使用されてきた。しかし本来、可変長レコードはエラーが発生しやすく、上記のことが役立つかどうか試してみるのも有益である。
MySQL に root
パスワードを設定しないと、root
として接続した場合に、サーバがパスワードを一切要求しなくなります。ユーザごとに常にパスワードを設定することをお勧めします。
See 項4.3.2. 「MySQL のクラッカー対策」。
root
パスワードを設定した後で、それを忘れてしまった場合、以下の手順で新しいパスワードを設定することができます。
mysqld
サーバに
kill
(kill -9
以外)を送り、mysqld
サーバを停止します。pid が
.pid
ファイルに格納されています。このファイルは通常、MySQL
データベースディレクトリにあります。
shell> kill `cat /mysql-data-directory/hostname.pid`
これを行うには、Unix root
ユーザまたは mysqld
が実行しているユーザと同じでなければなりません。
--skip-grant-tables
オプションを指定して mysqld
を再起動します。
mysqladmin password
コマンドで新しいパスワードを設定します。
shell> mysqladmin -u root password 'mynewpassword'
これで、適切に mysqld
を停止し再起動するか、以下のように、アクセス権テーブルをロードできるようになります。
shell> mysqladmin -h hostname flush-privileges
この後、新しいパスワードを使用して接続できます。
もう一つの方法として、mysql
クライアントを使用して新しいパスワードを設定することができます。
上述したように、mysqld
を停止して、--skip-grant-tables
オプションを指定して再起動します。
以下のように、mysqld
サーバに接続します。
shell> mysql -u root mysql
mysql
クライアントで以下のコマンドを実行します。
mysql>UPDATE user SET Password=PASSWORD('mynewpassword')
->WHERE User='root';
mysql>FLUSH PRIVILEGES;
この後、新しいパスワードを使用して接続できます。
これで、適切に mysqld
を停止し、再起動できます。
ディスクフル状態が発生した場合、MySQL では以下のことを行います。
1 分ごとに 1 回、現在のレコードを書き込むために十分な空き領域があるかどうか確認する。十分な空き領域がある場合は、何も問題が発生しなかったように処理を続行する。
6 分ごとにログファイルにエントリを書き込み、ディスクフル状態を警告する。
問題を軽減するために、以下を行うことができます。
処理を続行するには、全レコードを挿入できるディスク領域を確保する必要がある。
スレッドを停止するには、mysqladmin
kill
をスレッドに送信する必要がある。
スレッドは、次にディスクがチェックされたとき(1分)に停止する。
他のスレッドが、ディスクフル状態の原因となったテーブルを待機している可能性がある。複数の ``ロック'' スレッドがある場合、ディスクフル状態で待機しているスレッドを 1 つ強制終了すると、他のスレッドの処理を続行できる。
上記の動作の例外は、REPAIR
または OPTIMIZE
を使用しているときか、インデックスが
LOAD DATA INFILE
または ALTER
TABLE
ステートメントの後にバッチで作成されるときです。
上記のコマンドはすべて、大きなテンポラリファイルを使用する場合があるので、資源が残り少なくなったシステムに問題を引き起こす可能性があります。上記の操作を実行中に
MySQL
がディスクフル状態になると、大きなテンポラリファイルが削除され、テーブルはクラッシュしたものとしてマークされます(旧テーブルが変更されずに残る
ALTER TABLE
は除きます)。
MySQL
は、テンポラリファイルを格納するディレクトリのパス名として、TMPDIR
環境変数の値を使用します。TMPDIR
を設定していない場合、MySQL
はシステムのデフォルトを使用します。システムのデフォルトは、通常
/tmp
または
/usr/tmp
です。テンポラリファイルディレクトリを含むファイルシステムが非常に小さい場合、mysqld_safe
を編集して、領域が十分あるファイルシステムのディレクトリを指すように
TMPDIR
を設定する必要があります。mysqld
に対して --tmpdir
オプションを使用しても、テンポラリディレクトリを設定できます。
MySQL
はすべてのテンポラリファイルを隠しファイルとして作成します。これによって、mysqld
が強制終了されるとテンポラリファイルは確実に削除されます。隠しファイル使用の不利な点は、テンポラリファイルディレクトリのあるファイルシステムをいっぱいにするような大きなテンポラリファイルが見えないことです。
ソート時(ORDER BY
または
GROUP BY
により)、MySQL
は通常、1つまたは2つのテンポラリファイルを使用します。必要な最大ディスク領域は、以下のとおりです。
(ソートされたものの長さ + sizeof(データベースポインタ)) * マッチするレコードの数 * 2
sizeof(データベースポインタ)
は、通常 4
ですが、大きいテーブルに対応するため、将来的に増える可能性があります。
SELECT
クエリの中には、MySQL が
テンポラリ SQL
テーブルを作成するものがあります。これらは隠しファイルではなく、SQL_*
という名前になります。
ALTER TABLE
では、元のテーブルと同じディレクトリにテンポラリテーブルが作成されます。
MySQL 4.1 以降を使用している場合、コロン
:
(Windows の場合はセミコロン
;
)で区切られたパスのリストを
--tmpdir
に設定することにより、複数の物理ディスク間で負荷を分散させることができます。この物理ディスクは、ラウンドロビン方式で使用されます。
注意:
これらのパスは、同一ディスクの複数のパーティションではなく、異なる物理ディスクである必要があります。
tmpdir
を設定してメモリベースのファイルシステムを指定することは可能ですが、MySQL
サーバがスレーブの場合はできません。スレーブの場合、コンピュータの再起動用に、いくつかのテンポラリファイルが必要(テンポラリテーブルまたは
LOAD DATA INFILE
のレプリケーションため)です。そのため、コンピュータの再起動で消去されるメモリベースの
tmpdir
は適しません。ディスクベースの
tmpdir
が必要です。
すべての人が MySQL 通信ソケット
/tmp/mysql.sock
を削除できるということが問題であれば、Unix
の多くのバージョンにおいて、/tmp
ファイルシステムに sticky
ビットを設定することにより、そのファイルシステムを保護できるようになっています。root
としてログインし、以下を行います。
shell> chmod +t /tmp
これによって、/tmp
ファイルシステムが保護され、ファイルの所有者かスーパーユーザ(root
)しかファイルを削除できなくなります。
ls -ld /tmp
を実行して、sticky
ビットが設定されているかどうかを確認できます。
最後のアクセス権ビットが t
であれば、ビットは設定されています。
MySQL がソケットファイルを使用または置く場所を、以下の方法で変更できます。
グローバルオプション設定ファイルまたはローカルオプション設定ファイルのパスを指定する。
たとえば、/etc/my.cnf
に置く場合
[client] socket=path-for-socket-file [mysqld] socket=path-for-socket-file
コマンドラインで
--socket=path-for-socket-file
オプションを使用して、mysqld_safe
と大部分のクライアントに対してソケットを置く場所を指定する。
ソケットファイルのパスを、MYSQL_UNIX_PORT
環境変数で指定する。
configure
を
--with-unix-socket-path=path-for-socket-file
オプションとともに使用して、パスを定義する。
See 項2.3.3. 「一般的な configure
オプション」。
以下のコマンドで、ソケットの動作をテストできます。
shell> mysqladmin --socket=/path/to/socket version
SELECT NOW()
が現地時間ではなく GMT
の値を返す場合、現在のタイムゾーンに
TZ
環境変数を設定する必要があります。サーバが動作している環境(たとえば
mysqld_safe
または
mysqld_safe
)に対して設定を行ってください。
See 付録?F. 環境変数。
デフォルトでは、MySQL
検索では大文字と小文字は区別されませんが(ケース非依存)、中には、ケース依存のキャラクタセット(czech
)もあります。
つまり、col_name LIKE 'a%'
で検索すると、A
または
a
で始まる全カラムの値が検出されます。これをケース依存にする場合は、INSTR(col_name,
"A")=1
としてプリフィックスをチェックします。または、カラム値が確実に
"A"
でなければならない場合は、STRCMP(col_name,
"A") = 0
を使用します。
簡単な比較演算(>=、>、=、<、<=
、ソートおよびグループ化)は、各文字の
``ソート値''
に基づいています。同じソート値のある文字(E、e
および e
など)は、同じ文字として扱われます。
旧 MySQL バージョンでは、LIKE
比較は、各文字の大文字の値(E == e but E <>
e)で実行されました。新しい MySQL
バージョンでは、LIKE
は他の比較演算と同じように動作します。
カラムを常にケース依存で扱う場合は、BINARY
として宣言します。 See
項6.5.3. 「CREATE TABLE
構文」。
Big5
と呼ばれるエンコードで中国語データを使用している場合、すべての文字カラムを
BINARY
にします。Big5
エンコード文字のソート順序は ASCII
コードの順序に基づいているため、これが機能します。
DATE
値の書式は
'YYYY-MM-DD'
です。標準 SQL
では、他の書式は使用できません。この書式は、UPDATE
式と SELECT
ステートメントの WHERE
節で使用してください。たとえば、以下のように使用します。
mysql> SELECT * FROM tbl_name WHERE date >= '1997-05-05';
日付が数値コンテキストで使用されている場合は、利便性を考えて、MySQL
は日付を数値に自動的に変換します(逆の場合も同様です)。更新時や
WHERE
節で ``柔軟な''
文字列書式を使用できるので、日付を
TIMESTAMP
、DATE
または
DATETIME
カラムと比較することもできます(柔軟な書式とは、どんな句読文字もパート間の区切り記号として使用できる書式のことを言います。たとえば、'1998-08-15'
と '1998#08#15'
は同一です)。また
MySQL
は、区切り記号を含まない文字列(たとえば
'19980815'
)も、それが日付として理解できる場合は変換することができます。
特別な '0000-00-00'
日付は、'0000-00-00'
として格納し取り出すことができます。MyODBC
を介して '0000-00-00'
日付を使用している場合、MyODBC
バージョン 2.40.12 以上では自動的に
NULL
に変換されます。
MySQL は上述の変換を実行するため、以下のステートメントを使用します。
mysql>INSERT INTO tbl_name (idate) VALUES (19970505);
mysql>INSERT INTO tbl_name (idate) VALUES ('19970505');
mysql>INSERT INTO tbl_name (idate) VALUES ('97-05-05');
mysql>INSERT INTO tbl_name (idate) VALUES ('1997.05.05');
mysql>INSERT INTO tbl_name (idate) VALUES ('1997 05 05');
mysql>INSERT INTO tbl_name (idate) VALUES ('0000-00-00');
mysql>SELECT idate FROM tbl_name WHERE idate >= '1997-05-05';
mysql>SELECT idate FROM tbl_name WHERE idate >= 19970505;
mysql>SELECT MOD(idate,100) FROM tbl_name WHERE idate >= 19970505;
mysql>SELECT idate FROM tbl_name WHERE idate >= '19970505';
ただし、以下は動作しません。
mysql> SELECT idate FROM tbl_name WHERE STRCMP(idate,'19970505')=0;
STRCMP()
は文字列関数なので、idate
が文字列に変換され、文字列比較が実行されます。'19970505'
は日付に変換されず、日付比較も実行されません。
MySQLは、日付が正しいかどうかという非常に限定された確認しか行いません。'1998-2-31'
のような不正な日付を格納すると、間違った日付が格納されます。
MySQL は、日付を圧縮して保存するため、結果バッファに適合しない特定の日付は格納できません。日付の受け入れ規則は、以下のとおりです。
MySQL
が任意の日付を格納し取り出せる場合、DATE
と DATETIME
カラムは間違った日付を受けつける。
0 ? 31 のすべての値は、どんな日付にも受け入れられる。これは、3 つの別々のフィールドで年、月、日を保存する Web アプリケーションでは非常に便利である。
日または月フィールドをゼロにすることもできる。これは、DATE
カラムに生年月日を格納する場合で、日付の一部しか知らないときに便利である。
日付を適切な値に変換できない場合は、0
が DATE
フィールドに格納され、0000-00-00
として取り出されます。データベースが行うことは、ユーザが格納した日付と同じものを取り出すことなので(日付が論理的に正しくない場合でも)、これはスピードと利便性両方の問題になります。
我々は、日付を確認するのはサーバではなくアプリケーションの責任であると考えています。
NULL
値というものを SQL
初心者はよく混乱します。SQL
初心者は、多くの場合、NULL
が空文字 ""
と同じであると考えてしまいます。これは違います。たとえば、以下のステートメントは完全に別のものです。
mysql>INSERT INTO my_table (phone) VALUES (NULL);
mysql>INSERT INTO my_table (phone) VALUES ("");
どちらのステートメントも、値を
phone
カラムに挿入しています。しかし、最初のステートメントは
NULL
値を挿入し、2
つ目は空文字を挿入しています。最初のステートメントは
``電話番号が不明''
であると考えることができ、2番目は``電話を持っていない''
と考えることができます。
SQL では、NULL
値は、他の値と比較すると(NULL
でも)常に偽になります。NULL
を含む式は、演算子と式に含まれている関数のドキュメントに特に断りがなければ、常に
NULL
値を生成します。以下の例では、全カラムが
NULL
を返します。
mysql> SELECT NULL,1+NULL,CONCAT('Invisible',NULL);
NULL
のカラム値を検索したい場合、=NULL
テストは使用できません。どんな式でも
expr = NULL
は偽なので、以下のステートメントはレコードを返しません。
mysql> SELECT * FROM my_table WHERE phone = NULL;
NULL
値を検出するには、IS
NULL
テストを使用します。
以下から、NULL
の電話番号と空の電話番号の検索方法がわかります。
mysql>SELECT * FROM my_table WHERE phone IS NULL;
mysql>SELECT * FROM my_table WHERE phone = "";
MySQL バージョン 3.23.2 以降を使用し、かつ
MyISAM
、InnoDB
、BDB
テーブル型を使用している場合に限り、NULL
値を持つことができるカラムのインデックスを追加することができます。
以前のバージョンや別のテーブル型では、NOT
NULL
などのカラムを宣言する必要があります。これは、NULL
をインデックス化されたカラムに挿入できないということでもあります。
LOAD DATA INFILE
でデータを読み取ると、空のカラムは
''
で更新されます。カラムに
NULL
値が必要な場合は、テキストファイルで
\N
を使用してください。状況によっては、リテラル文字
'NULL'
も使用されます。 See
項6.4.8. 「LOAD DATA INFILE
構文」。
ORDER BY
を使用する際、降順でソートするように
DESC
を指定すると、NULL
値が最初または最後に表示されます。例外: MySQL
バージョン 4.0.2 から 4.0.10
では、ソート順序に関わらず NULL
値は 1 番目にソートされます。
GROUP BY
を使用すると、すべての
NULL
値が同じと見なされます。
COUNT()
、MIN()
、SUM()
などの集約(要約)関数では、NULL
値は無視されます。例外は COUNT(*)
です。この関数は、個々のカラム値ではなくレコードをカウントします。
たとえば、以下のステートメントでは
2つのカウントが行われます。
最初は、テーブルにあるレコード数のカウントです。2
番目は age
カラムにある非
NULL
値のカウントです。
mysql> SELECT COUNT(*), COUNT(age) FROM person;
NULL
処理を補うために、IS
NULL
と IS NOT NULL
演算子と
IFNULL()
関数を使用することができます。
カラム型の中には、NULL
値が特別に扱われるものがあります。テーブルの最初のカラム
TIMESTAMP
に NULL
を挿入すると、現在の日付と時刻が挿入されます。AUTO_INCREMENT
カラムに NULL
を挿入すると、順番の次の番号が挿入されます。
エイリアスを使用して、GROUP
BY
、ORDER BY
または
HAVING
部分のカラムを参照することができます。エイリアスを使用して、カラムにわかりやすい名前を付けることもできます。
SELECT SQRT(a*b) as rt FROM table_name GROUP BY rt HAVING rt > 0; SELECT id,COUNT(*) AS cnt FROM table_name GROUP BY id HAVING cnt > 0; SELECT id AS "Customer identity" FROM table_name;
標準 SQL では、WHERE
節のエイリアスを参照することはできません。これは、WHERE
コードが実行される際、カラム値がまだ設定されていない場合があるためです。たとえば、以下のクエリは無効です。
SELECT id,COUNT(*) AS cnt FROM table_name WHERE cnt > 0 GROUP BY id;
WHERE
ステートメントを実行して
GROUP BY
部分に追加するレコードを決定し、HAVING
を実行して結果セットからどのレコードを使用するか決定します。
MySQL
では、サブクエリをサポートしていません(バージョン
4.1 より前)。また、DELETE
ステートメントでの 2
つ以上のテーブルの使用もサポートしていません(バージョン
4.0 より前)。そのため、2
つの関連テーブルからレコードを削除するには、以下の方法を使用してください。
メインテーブルで WHERE
条件に基づいて、レコードを
SELECT
する。
同じ条件に基づいて、メインテーブルのレコードを
DELETE
する。
DELETE FROM related_table WHERE related_column IN
(selected_rows)
。
related_column
のクエリの合計文字数が
1,048,576(max_allowed_packet
のデフォルト値)を超える場合、分割して、複数回
DELETE
ステートメントを実行してください。related_column
がインデックスの場合は、100 ? 1000 の
related_column
ID
を削除するだけなので、通常
DELETE
が非常に速くなります。related_column
がインデックスでない場合、速度は
IN
節の引数の数に依存しません。
多くのテーブルが含まれる複雑なクエリを使用していて、それがレコードを返さない場合、以下の手順でクエリの問題を見つける必要があります。
EXPLAIN
でクエリをテストし、明らかに問題と思われる箇所があるか確認する。
See 項5.2.1. 「EXPLAIN
構文(SELECT
に関する情報の取得)」。
WHERE
節で使用されるフィールドだけを選択する。
レコードが返るまで、クエリから 1 つ 1
つテーブルを削除する。
テーブルが大きい場合に有効なのは、クエリで
LIMIT 10
を使用する方法である。
クエリから最後に削除されたテーブルに対してレコードが一致したカラムに、
SELECT
を実行する。
FLOAT
または DOUBLE
カラムを小数と比較している場合、'='
は使用できない。浮動小数点の値は正確な値ではない。この問題は大部分のコンピュータ言語で共通。
たいていの場合、FLOAT
を
DOUBLE
に変更すると問題は解決する。 See
項A.5.7. 「浮動小数点比較の問題」。
それでも問題が解決できない場合は、mysql
test < query.sql
で実行できる小さなテストを作成して、問題を表示する。
mysqldump --quick database tables >
query.sql
で、テストファイルを作成できる。エディタでファイルを開き、数が多ければいくつかの挿入行を削除する。そして、ファイルの最後に
SELECT
ステートメントを追加する。
まだ問題が残っているかどうか、以下の方法でテストしてください。
shell>mysqladmin create test2
shell>mysql test2 < query.sql
mysqlbug
を使用して、テストファイルを汎用 MySQL
メーリングリストに投稿してください。 See
項1.7.1.1. 「MySQL メーリングリスト」。
浮動小数点数は、コンピュータアーキテクチャ内部では正確な値として格納されないため、混乱を引き起こす場合があります。通常画面に表示される値は、正確な値ではありません。
フィールドタイプ
FLOAT
、DOUBLE
、および
DECIMAL
が該当します。
CREATE TABLE t1 (i INT, d1 DECIMAL(9,2), d2 DECIMAL(9,2)); INSERT INTO t1 VALUES (1, 101.40, 21.40), (1, -80.00, 0.00), (2, 0.00, 0.00), (2, -13.20, 0.00), (2, 59.60, 46.40), (2, 30.40, 30.40), (3, 37.00, 7.40), (3, -29.60, 0.00), (4, 60.00, 15.40), (4, -10.60, 0.00), (4, -34.00, 0.00), (5, 33.00, 0.00), (5, -25.80, 0.00), (5, 0.00, 7.20), (6, 0.00, 0.00), (6, -51.40, 0.00); mysql>SELECT i, SUM(d1) AS a, SUM(d2) AS b
->FROM t1 GROUP BY i HAVING a <> b;
+------+--------+-------+ | i | a | b | +------+--------+-------+ | 1 | 21.40 | 21.40 | | 2 | 76.80 | 76.80 | | 3 | 7.40 | 7.40 | | 4 | 15.40 | 15.40 | | 5 | 7.20 | 7.20 | | 6 | -51.40 | 0.00 | +------+--------+-------+
結果は正確です。最初の 5 つのレコードは比較テストにパスしないように見えますがパスできます。コンピュータアーキテクチャによりますが、数の差異は、小数点第 10 位くらいで現れるためです。
結果は浮動小数点数なので、ROUND( )(または同様の関数)を使用して問題を解決することはできません。たとえば、以下のとおりです。
mysql>SELECT i, ROUND(SUM(d1), 2) AS a, ROUND(SUM(d2), 2) AS b
->FROM t1 GROUP BY i HAVING a <> b;
+------+--------+-------+ | i | a | b | +------+--------+-------+ | 1 | 21.40 | 21.40 | | 2 | 76.80 | 76.80 | | 3 | 7.40 | 7.40 | | 4 | 15.40 | 15.40 | | 5 | 7.20 | 7.20 | | 6 | -51.40 | 0.00 | +------+--------+-------+
カラム 'a' 内の数は以下のようになります。
mysql>SELECT i, ROUND(SUM(d1), 2)*1.0000000000000000 AS a,
->ROUND(SUM(d2), 2) AS b FROM t1 GROUP BY i HAVING a <> b;
+------+----------------------+-------+ | i | a | b | +------+----------------------+-------+ | 1 | 21.3999999999999986 | 21.40 | | 2 | 76.7999999999999972 | 76.80 | | 3 | 7.4000000000000004 | 7.40 | | 4 | 15.4000000000000004 | 15.40 | | 5 | 7.2000000000000002 | 7.20 | | 6 | -51.3999999999999986 | 0.00 | +------+----------------------+-------+
コンピュータアーキテクチャによって、同じ結果が表示されたりされなかったりします。 CPU ごとに浮動小数点数の評価方法が異なります。たとえばマシンの中には、両方の引数を 1 で掛け合わすと '正確な' 結果を得られるものがあります。たとえば以下のようになります。
警告: あなたのアプリケーションでは、この方法を決して信用しないでください。これは間違った方法の例です。
mysql>SELECT i, ROUND(SUM(d1), 2)*1 AS a, ROUND(SUM(d2), 2)*1 AS b
->FROM t1 GROUP BY i HAVING a <> b;
+------+--------+------+ | i | a | b | +------+--------+------+ | 6 | -51.40 | 0.00 | +------+--------+------+
上記の例が動作するように見える理由は、テストが実行されたマシンで、CPU 浮動小数点演算が複数の数字を偶然同じ数字に四捨五入してしまうことにあります。しかし、CPU がそうしなければならないという規則はないため、この例は信用できません。
浮動小数点数比較を行う正しい方法は、まず数の許容範囲を決定し、続いて許容範囲の数に対して比較を行うことです。たとえば、浮動小数点数は同一と見なすということにすれば、それらが 10000 分の 1(0.0001)の精度で同じである場合、比較が以下のように行われます。
mysql>SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1
->GROUP BY i HAVING ABS(a - b) > 0.0001;
+------+--------+------+ | i | a | b | +------+--------+------+ | 6 | -51.40 | 0.00 | +------+--------+------+ 1 row in set (0.00 sec)
逆に、数が同じになるレコードを取得したい場合は、テストは次のようになります。
mysql>SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1
->GROUP BY i HAVING ABS(a - b) < 0.0001;
+------+-------+-------+ | i | a | b | +------+-------+-------+ | 1 | 21.40 | 21.40 | | 2 | 76.80 | 76.80 | | 3 | 7.40 | 7.40 | | 4 | 15.40 | 15.40 | | 5 | 7.20 | 7.20 | +------+-------+-------+
MySQL はオプティマイザを使用して、クエリを解決する最も優れた方法を見つけ出します。多くの場合、MySQL は最も可能性のあるクエリを見積もることができますが、場合によってはデータに関する十分な情報が手元にないので、経験に基づく '推測' を行う必要があります。
ここでは、MySQL が正しく理解しない場合を扱います。
MySQL が '正しく' 最適化するのに役立つツールは、以下のとおりです。
EXPLAIN
。 See 項5.2.1. 「EXPLAIN
構文(SELECT
に関する情報の取得)」。
ANALYZE TABLE
。 See
項4.6.2. 「ANALYZE TABLE
構文」。
USE INDEX
, FORCE INDEX
および IGNORE INDEX
。 See
項6.4.1. 「SELECT
構文」。
グローバルおよびテーブルレベルの
STRAIGHT JOIN
。 See
項6.4.1. 「SELECT
構文」。
スレッド固有の変数の設定。 See
項4.6.8.4. 「SHOW VARIABLES
」。
MySQL
がテーブルスキャンを使用してクエリを解決した場合、EXPLAIN
では type
カラム内に
ALL
が表示されます。これは、通常以下の場合に起こります。
テーブルが小さく、キー走査よりもテーブルスキャンを行う方が速い場合。 これは、レコードの数が 10 未満で、レコードの長さが短いテーブルではよくあるケースである。
ON
または WHERE
節に、インデックスを張ったカラムを利用する条件がない場合。
インデックスを張ったカラムと変数を比較中に、MySQL
が(インデックスツリーに基づいて)、変数がテーブルの大部分の範囲に及んでいるためテーブルスキャンの方が速いと予測した場合。
See 項5.2.4. 「MySQL による WHERE
節の最適化」。
別のカラムを介して、下位の基数(= 多くの一致レコード)でキーを使用している場合。この場合、MySQL は、そのキーを使用して多くのキールックアップが行われると見なし、テーブルスキャンの方が早いと見なす。
大きなテーブルの '不正な' テーブルスキャンを回避するには、以下のことを行います。
スキャンテーブルに対して ANALYZE
TABLE
を使用し、キーの分布を更新する。 See
項4.6.2. 「ANALYZE TABLE
構文」。
スキャンテーブルに対して FORCE
INDEX
を使用し、テーブルのスキャンは、特定のインデックスの使用と比較すると非常に処理の負荷が高いことを、MySQL
に通知する。 See 項6.4.1. 「SELECT
構文」。
SELECT * FROM t1,t2 force index(index_for_column) WHERE t1.column=t2.column;
--max-seeks-for-key=1000
を指定して
mysqld
を起動するか SET
MAX_SEEKS_FOR_KEY=1000
を行って、オプティマイザに、キースキャンで
1000
を越すキー検索が行われないことを告げる。
ALTER TABLE
によって、テーブルが現在のキャラクタセットに変更されます。
ALTER TABLE
中に duplicate key error
が発生する場合、新しいキャラクタセットが 2
つのキーを同じ値にマップしているか、テーブルが壊れています。テーブルが壊れている場合は、そのテーブルで
REPAIR TABLE
を実行してください。
以下のようなエラーで ALTER TABLE
が強制終了される場合
Error on rename of './database/name.frm' to './database/B-a.frm' (Errcode: 17)
原因として、MySQL が前回の ALTER
TABLE
でクラッシュしており、使用されていない
A-something
または
B-something
という名前の古いテーブルがあることが考えられます。この場合、MySQL
データディレクトリに移り、A-
または B-
で始まる名前のファイルをすべて削除してください(削除しないで別の場所に移動することもできます)。
ALTER TABLE
は、以下のように動作します。
変更要求のあった A-xxx
という名前の新しいテ-ブルを作成する。
旧テーブルのすべてのレコードが
A-xxx
にコピーされる。
旧テーブル名が B-xxx
に変更される。
A-xxx
が旧テーブル名に変更される。
B-xxx
が削除される。
名前変更操作に何か問題が発生した場合は、MySQL
は変更を取り消します。致命的な問題が発生した場合(もちろん起こってはならないことですが)、MySQL
は旧テーブルを B-xxx
のままにしておく可能性がありますが、システムレベルでの簡単な名前変更でデータは元に戻ります。
SQL の主な目的は、データストレージから要求した情報を抽出することです。必ず、データを取り出す順序を指定する必要があります。たとえば、以下のようになります。
SELECT col_name1, col_name2, col_name3 FROM tbl_name;
上記は、col_name1
、col_name2
、col_name3
の順序でカラムを返します。
SELECT col_name1, col_name3, col_name2 FROM tbl_name;
上記の場合、col_name1
、col_name3
、col_name2
の順序でカラムを返します。
カラム順序は、以下のように変更できます。
正しい順序のカラムで新しいテーブルを作成する。
INSERT INTO new_table SELECT
fields-in-new_table-order FROM old_table
を実行する。
old_table
を廃棄するか、名前変更する。
ALTER TABLE new_table RENAME old_table
。
カラムを追加、移動、削除する場合、カラムが返される順序と位置が同じにならないので、アプリケーションで、SELECT
*
を使用してその位置に依存するカラムを絶対に取り出さないでください。データベース構造に簡単な変更を加えるだけでも、アプリケーションエラーが発生します。
もちろん SELECT *
は、クエリのテストに最適です。
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.