Go to the first, previous, next, last section, table of contents.


A 問題と一般的なエラー

この章では、ユーザが遭遇するいくつかの一般的な問題とエラーメッセージについて説明しています。どんな問題か見分ける方法と、問題を解決するために行わなければならないことがわかります。また、一般的な問題の適切な解決方法についても記載されています。

A.1 問題の原因を突き止める方法

問題に遭遇した場合、まず、問題の原因となっているプログラムまたは装置を突き止めます。

他の可能性をすべて調査し、問題の原因となっているのが MySQL サーバか MySQL クライアントであると結論づいた場合には、弊社メーリングリストまたはサポートチームにバグレポートをお送りください。バグレポートには、システムの動作、および発生していると考えられることを、詳細に記載してください。また、問題の原因が MySQL であると考えられる理由についても記入してください。この章のすべての状況を考慮に入れてください。システムを調査したときに、問題がどのように発生したかを正確に記入してください。プログラムまたはログファイルの出力またはエラーメッセージを記入する場合は、'カット & ペースト' を使用してください。

動作していないプログラムおよびすべての症状を詳細に記述するようにしてください。過去、"システムが動作しない" としか記述されていないバグレポートを多く受け取りました。これでは、何が問題なのかわかりません。

プログラムが失敗する場合は、以下を確認すると役立ちます。

バグレポートをお送りいただく際には、このマニュアルに記載されている原則に従ってください。 See section 1.7.1.2 質問またはバグの報告

A.2 MySQL 使用時によくあるエラー

このセクションでは、頻繁に発生するいくつかのエラーについて説明します。エラーの内容と問題の解決方法を説明します。

A.2.1 Access denied エラー

See section 4.3.13 Access denied エラーの原因。 See section 4.3.6 権限システムはどのように機能するか

A.2.2 MySQL server has gone away エラー

このセクションでは、関連する 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 section A.4.1 MySQL が何度もクラッシュする場合に行うこと

間違ったクエリか大きすぎるクエリをサーバに送信した場合も、このエラーが発生する可能性があります。mysqld は大きすぎるか異常のあるパケットを取得すると、クライアントに何か問題が発生したとみなし、接続をクローズします。大きなクエリが必要な場合(たとえば、大きな BLOB カラムを使用している場合)、mysqld-O max_allowed_packet=# オプション(デフォルト 1MB)で起動して、クエリ制限を引き上げることができます。拡張メモリは要求に応じて割り当てられます。そのため、mysqld は、ユーザが大きなクエリを発行するときや、mysqld が大きな結果レコードを返す必要のあるときだけ、メモリを増やして割り当てます。

クライアントが 4.0.8 より古く、サーバが 4.0.8 以上の場合、またはその逆の場合、16MB 以上のパケットを送信すると接続が失われます。

この問題についてバグレポートを作成する際には、必ず以下の情報を記入してください。

See section 1.7.1.2 質問またはバグの報告

A.2.3 Can't connect to [local] MySQL server エラー

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 section 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 エラーが発生する理由として、以下のことが考えられます。

エラーメッセージ Can't connect to MySQL server on some_hostname が発生した場合は、以下を行って問題を突き止めることができます。

A.2.4 Client does not support authentication protocol エラー

MySQL 4.1 では、パスワードハッシュアルゴリズムに基づく認証プロトコルが使用されていますが、これは旧クライアントが使用しているものと互換性がありません。 サーバを 4.1 にアップグレードすると、旧クライアントで接続しようとした場合に、以下のエラーメッセージが発生する可能性があります。

shell> mysql
Client does not support authentication protocol requested
by server; consider upgrading MySQL client

この問題を解決するには、以下のいずれかを行ってください。

パスワードハッシュと認証の背景については、section 4.3.11 MySQL 4.1 のパスワードハッシュ を参照してください。

A.2.5 Host '...' is blocked エラー

以下のエラーが発生した場合

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 変数の値を増やしても効果はありません。

A.2.6 Too many connections エラー

MySQL に接続しようとして Too many connections エラーが発生する場合は、すでに mysqld サーバに接続している max_connections クライアントが存在しています。

デフォルト(100)より多い接続を行う場合は、max_connections 変数の値を 100 より大きくして、mysqld を再起動する必要があります。

実際は、mysqld では(max_connections+1)クライアントの接続が許可されています。最後の接続は、SUPER 特権のあるユーザ用に予約されています。一般ユーザにこの特権を与えないことによって(一般ユーザにこの特権は必要ありません)、この特権のある管理者はログインして、SHOW PROCESSLIST を使用して問題を見つけることができます。 See section 4.6.8.6 SHOW PROCESSLIST

MySQL 接続の最大数は、スレッドライブラリが特定のプラットフォームでどの程度まで有用であるかに依存します。Linux または Solaris では、使用している RAM のサイズと、クライアントが何を実行しているかによって、500 〜 1000 の同時接続をサポートできます。

A.2.7 Some non-transactional changed tables couldn't be rolled back エラー

ROLLBACK を実行しようとしたときに Warning: Some non-transactional changed tables couldn't be rolled back が発生した場合、トランザクションで使用したテーブルの中にトランザクションをサポートしていないものがあることを示しています。これら非トランザクションテーブルは、ROLLBACK ステートメントからの影響を受けません。

最も一般的には、このエラーが発生するのは、mysqld バイナリでサポートされていない型のテーブルを作成しようとしたときです。 mysqld がテーブル型をサポートしていない場合(またはスタートアップオプションでテーブル型が無効化されている場合)、代わりに、要求したものと最も類似したテーブル型(おそらく MyISAM)が作成されます。

以下のコマンドでテーブルのテーブル型を確認できます。

SHOW TABLE STATUS LIKE 'table_name'。 See section 4.6.8.2 SHOW TABLE STATUS

以下のコマンドで mysqld バイナリがサポートする拡張子を確認できます。

SHOW VARIABLES LIKE 'have_%'。 See section 4.6.8.4 SHOW VARIABLES

A.2.8 Out of memory エラー

クエリを発行し、以下のようなエラーが発生した場合

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() を使用します。これによってクライアントの負荷が小さくなります(サーバ側では負荷が大きくなります)。

A.2.9 Packet too large エラー

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 を使用してください。 オプション設定ファイルを使用すると、mysqldmax_allowed_packet をより大きなサイズに設定することができます。たとえば、MEDIUMBLOB の許容範囲いっぱいのデータをテーブルに入れる場合、--set-variable=max_allowed_packet=16M オプションを指定してサーバを起動します。

大きな BLOB を使用している場合、大きなパケットに関する見慣れない問題が発生する可能性がありますが、これは、mysqld に、そのクエリを処理できるだけの十分なメモリへのアクセス権がないことが原因です。その場合は、mysqld_safe スクリプトの始めに ulimit -d 256000 を追加して、mysqld を再起動してください。

A.2.10 通信エラー/Aborted connection

MySQL 3.23.40 から、mysqld--warnings で開始した場合のみ、Aborted connection エラーが発生します。

エラーログに以下のようなエラーが含まれている場合は、

010301 14:38:23  Aborted connection 854 to db: 'users' user: 'josh'

See section 4.10.1 エラーログ

以下が発生したと考えられます。

上記のことが発生した場合、サーバ変数 Aborted_clients の値が増えます。

以下の場合、サーバ変数 Aborted_connects の値が増えます。

上記のことは、不正ユーザがデータベースに侵入しようとしている可能性を示しています。

中止されたクライアントおよび中止された接続エラーのその他の原因

A.2.11 The table is full エラー

このエラーが発生するケースとしては、以下のようなさまざまなケースが考えられます。

A.2.12 Can't create/write to file エラー

以下のようなクエリのエラーが発生する場合

Can't create/write to file '\\sqla3fe_0.ism'.

MySQL が、特定のテンポラリディレクトリに結果セット用のテンポラリファイルを作成できないことを示しています(上記のエラーは、Windows での典型的なエラーメッセージですが、Unix でのエラーメッセージもよく似たメッセージになります)。 解決するには、--tmpdir=path を指定して mysqld を起動するか、オプション設定ファイルに以下のコードを追加します。

[mysqld]
tmpdir=C:/temp

`c:\\temp' ディレクトリが存在していると仮定しています。 See section 4.1.2 `my.cnf' オプション設定ファイル

また perror で、取得するエラーコードを確認します。1つの原因としてディスクがいっぱいになっていることも考えられます。

shell> perror 28
Error code  28:  No space left on device

A.2.13 クライアントでの Commands out of sync エラー

クライアントコードの中に Commands out of sync; you can't run this command now がある場合は、間違った順序でクライアント関数を呼び出しています。

たとえば、mysql_free_result() を呼び出す前に mysql_use_result() を使って新しいクエリを実行しようとすると、上記のことが起こる可能性があります。 また、データを返す 2つのクエリを、その間に mysql_use_result()mysql_store_result() を呼び出さないで実行した場合にも起こる可能性があります。

A.2.14 Ignoring user エラー

次のエラーが発生する場合

Found wrong password for user: 'some_user@some_host'; ignoring user

mysqld が再起動されたとき、またはアクセス権テーブルが再ロードされたときに、user テーブルに無効なパスワードのエントリが見つかったことを示しています。結果として、このエントリはアクセス権システムから無視されます。

この問題の考えられる原因と修正方法

A.2.15 Table 'xxx' doesn't exist エラー

エラー Table 'xxx' doesn't exist または Can't find file: 'xxx' (errno: 2) が発生する場合、xxx という名前のカレントデータベースにテーブルがないことを示しています。

MySQL では、データベースとテーブルの格納にディレクトリとファイルを使用するため、データベースとテーブル名は、大文字と小文字の区別がある(ケース依存)ことに注意してください (Windows では、データベースとテーブル名に大文字小文字の区別がありません。しかし、クエリ内の特定テーブルへの参照では大文字と小文字を完全に合わせる必要があります)。

SHOW TABLES を使用して、カレントデータベースにあるテーブルを確認できます。 See section 4.6.8 SHOW 構文

A.2.16 Can't initialize character set xxx エラー

以下のエラーが発生した場合

MySQL Connection Failed: Can't initialize character set xxx

以下のことが考えられます。

A.2.17 File Not Found エラー

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 section 4.6.8.4 SHOW VARIABLES。 これを行う最も簡単な方法は、オプション設定ファイルにオプションを追加することです。 See section 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_safesh で開始する必要があります。

A.3 インストール関連の問題

A.3.1 MySQL クライアントライブラリにリンク時の問題

プログラムをリンクするときに、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 section 2.3 MySQL ソースディストリビューションのインストール

プログラムを実行しようとしているが、mysql_ で始まるエラーか、mysqlclient ライブラリが見つからない未参照シンボルのエラーが発生する場合は、システムが `libmysqlclient.so' 共有ライブラリを見つけられないということを示しています。

これを解決するには、以下のいずれかの方法で、関数が組み込まれている共用ライブラリを検索するように、システムに指示します。

この問題を解決するもう 1つの方法として、-static を使用するか、コードをリンクする前に MySQL の動的ライブラリを削除して、プログラムを静的にリンクする方法があります。2 番目のケースでは、別のプログラムが動的ライブラリを使用していないことを確認する必要があります。

A.3.2 一般ユーザで MySQL を実行する方法

MySQL サーバ mysqld は、どんな Unix ユーザでも開始、実行できます。 mysqld を Unix ユーザ user_name で実行できるように変更するには、以下を行ってください。

  1. サーバが動作している場合は、それを停止します(mysqladmin shutdown を使用します)。
  2. データベースのディレクトリとファイルを変更して、その中のファイルを読み込んだり書き込んだりする権限を user_name に与えます(場合によっては Unix root ユーザとして行う必要があります)。
    shell> chown -R user_name /path/to/mysql/datadir
    
    MySQL データディレクトリ内のディレクトリまたはファイルがシンボリックリンクの場合は、リンクに従い、そのファイルやディレクトリが指しているディレクトリとファイルも変更する必要があります。chown -R では、シンボリックリンク先まで変更できません。
  3. サーバを user_name で開始するか、MySQL バージョン 3.22 以降を使用している場合は、mysqld をUnix root ユーザで開始して、--user=user_name オプションを使用します。mysqld は、接続を許可する前に、Unix ユーザ user_name での実行に切り替わります。
  4. システム起動時にサーバを特定のユーザ名で自動的に開始するには、ユーザ名を指定する 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 を実行して思い通りのことを行えます。

A.3.3 ファイルアクセス権の問題

ファイルアクセス権に問題がある場合、たとえばテーブルを作成する際に 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 変数を設定して、この動作を変更することができます。この変数を設定すると、UMASKUMASK_DIR が組み合わされて新しいディレクトリが作成されます。たとえば新しいディレクトリすべてにグループアクセス権を与える場合は、以下を実行します。

shell> UMASK_DIR=504  # = 8進数で 770
shell> export UMASK_DIR
shell> /path/to/mysqld_safe &

MySQL バージョン 3.23.25 以降では、UMASKUMASK_DIR の値がゼロで始まる場合、MySQL はその値を8進数と仮定します。

See section F 環境変数

A.4 管理関連の問題

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

MySQL バージョンはすべて、リリース前に多くのプラットフォームでテストされています。これは MySQL にバグがないというわけではありませんが、バグがあったとしても、非常に少なく見つけるのが困難です。何か問題がある場合に、システムをクラッシュさせているものを正確に調査することは、この問題の早期解決に役立ちます。

まず、問題は mysqld デーモンが死んでいることにあるのか、または問題がクライアントに関係しているのかを判断する必要があります。mysqladmin version を実行して、mysqld サーバが稼動していた時間を確認することができます。mysqld が死んでいる場合は、ファイル `mysql-data-directory/`hostname`.err' を見ることによりその原因を見つけることができます。 See section 4.10.1 エラーログ

システムの中には、このファイルに mysqld が死んだ際のスタックトレースがあるものがあり、resolve_back_stack で問題を解決できます。See section E.1.4 スタックトレースの使用.err ファイルに書き込まれている変数値は、常に 100 パーセント正確であるとは限りません。

MySQL のクラッシュの多くは、インデックスファイルやデータファイルの破壊が原因です。 MySQL は、すべての SQL ステートメントの後で write() システムコールを呼び出し、ディスク上のデータを更新します。クライアントには、その後その結果が通知されます(delay_key_write で実行している場合で、データの書き込みだけの場合にはこの限りではありません)。 つまり、OS によってフラッシュされていないデータがディスクに確実に書き込まれるため、mysqld がクラッシュした場合でもデータは安全です。--flush を指定して mysqld を開始することによって、各 SQL コマンド実行後、強制的にすべてをディスクと同期させることができます。

つまり、以下のことがなければ、通常は破壊されたテーブルを得ることはありません。

クラッシュの原因を見つけるのは非常に難しいので、まず、他で動作しているものが自分の環境でクラッシュするかどうかを確認してください。以下を試してください。

A.4.2 忘れたルートパスワードをリセットする方法

MySQL に root パスワードを設定しないと、root として接続した場合に、サーバがパスワードを一切要求しなくなります。ユーザごとに常にパスワードを設定することをお勧めします。 See section 4.3.2 MySQL のクラッカー対策

root パスワードを設定した後で、それを忘れてしまった場合、以下の手順で新しいパスワードを設定することができます。

  1. mysqld サーバに killkill -9 以外)を送り、mysqld サーバを停止します。pid が `.pid' ファイルに格納されています。このファイルは通常、MySQL データベースディレクトリにあります。
    shell> kill `cat /mysql-data-directory/hostname.pid`
    
    これを行うには、Unix root ユーザまたは mysqld が実行しているユーザと同じでなければなりません。
  2. --skip-grant-tables オプションを指定して mysqld を再起動します。
  3. mysqladmin password コマンドで新しいパスワードを設定します。
    shell> mysqladmin -u root password 'mynewpassword'
    
  4. これで、適切に mysqld を停止し再起動するか、以下のように、アクセス権テーブルをロードできるようになります。
    shell> mysqladmin -h hostname flush-privileges
    
  5. この後、新しいパスワードを使用して接続できます。

もう一つの方法として、mysql クライアントを使用して新しいパスワードを設定することができます。

  1. 上述したように、mysqld を停止して、--skip-grant-tables オプションを指定して再起動します。
  2. 以下のように、mysqld サーバに接続します。
    shell> mysql -u root mysql
    
  3. mysql クライアントで以下のコマンドを実行します。
    mysql> UPDATE user SET Password=PASSWORD('mynewpassword')
        ->             WHERE User='root';
    mysql> FLUSH PRIVILEGES;
    
  4. この後、新しいパスワードを使用して接続できます。
  5. これで、適切に mysqld を停止し、再起動できます。

A.4.3 フルディスク時の MySQL の動作

ディスクフル状態が発生した場合、MySQL では以下のことを行います。

問題を軽減するために、以下を行うことができます。

上記の動作の例外は、REPAIR または OPTIMIZE を使用しているときか、インデックスが LOAD DATA INFILE または ALTER TABLE ステートメントの後にバッチで作成されるときです。

上記のコマンドはすべて、大きなテンポラリファイルを使用する場合があるので、資源が残り少なくなったシステムに問題を引き起こす可能性があります。上記の操作を実行中に MySQL がディスクフル状態になると、大きなテンポラリファイルが削除され、テーブルはクラッシュしたものとしてマークされます(旧テーブルが変更されずに残る ALTER TABLE は除きます)。

A.4.4 MySQL がテンポラリファイルを格納する場所

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 が必要です。

A.4.5 MySQL ソケットファイル `/tmp/mysql.sock' の保護または変更方法

すべての人が MySQL 通信ソケット `/tmp/mysql.sock' を削除できるということが問題であれば、Unix の多くのバージョンにおいて、`/tmp' ファイルシステムに sticky ビットを設定することにより、そのファイルシステムを保護できるようになっています。root としてログインし、以下を行います。

shell> chmod +t /tmp

これによって、`/tmp' ファイルシステムが保護され、ファイルの所有者かスーパーユーザ(root)しかファイルを削除できなくなります。

ls -ld /tmp を実行して、sticky ビットが設定されているかどうかを確認できます。 最後のアクセス権ビットが t であれば、ビットは設定されています。

MySQL がソケットファイルを使用または置く場所を、以下の方法で変更できます。

以下のコマンドで、ソケットの動作をテストできます。

shell> mysqladmin --socket=/path/to/socket version

A.4.6 タイムゾーンの問題

SELECT NOW() が現地時間ではなく GMT の値を返す場合、現在のタイムゾーンに TZ 環境変数を設定する必要があります。サーバが動作している環境(たとえば mysqld_safe または mysqld_safe)に対して設定を行ってください。 See section F 環境変数

A.5 クエリ関連の問題

A.5.1 検索時のケース依存

デフォルトでは、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 section 6.5.3 CREATE TABLE 構文

Big5 と呼ばれるエンコードで中国語データを使用している場合、すべての文字カラムを BINARY にします。Big5 エンコード文字のソート順序は ASCII コードの順序に基づいているため、これが機能します。

A.5.2 DATE カラム使用時の問題

DATE 値の書式は 'YYYY-MM-DD' です。標準 SQL では、他の書式は使用できません。この書式は、UPDATE 式と SELECT ステートメントの WHERE 節で使用してください。たとえば、以下のように使用します。

mysql> SELECT * FROM tbl_name WHERE date >= '1997-05-05';

日付が数値コンテキストで使用されている場合は、利便性を考えて、MySQL は日付を数値に自動的に変換します(逆の場合も同様です)。更新時や WHERE 節で ``柔軟な'' 文字列書式を使用できるので、日付を TIMESTAMPDATE または 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 は、日付を圧縮して保存するため、結果バッファに適合しない特定の日付は格納できません。日付の受け入れ規則は、以下のとおりです。

日付を適切な値に変換できない場合は、0DATE フィールドに格納され、0000-00-00 として取り出されます。データベースが行うことは、ユーザが格納した日付と同じものを取り出すことなので(日付が論理的に正しくない場合でも)、これはスピードと利便性両方の問題になります。 我々は、日付を確認するのはサーバではなくアプリケーションの責任であると考えています。

A.5.3 NULL 値の問題

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 以降を使用し、かつ MyISAMInnoDBBDB テーブル型を使用している場合に限り、NULL 値を持つことができるカラムのインデックスを追加することができます。 以前のバージョンや別のテーブル型では、NOT NULL などのカラムを宣言する必要があります。これは、NULL をインデックス化されたカラムに挿入できないということでもあります。

LOAD DATA INFILE でデータを読み取ると、空のカラムは '' で更新されます。カラムに NULL 値が必要な場合は、テキストファイルで \N を使用してください。状況によっては、リテラル文字 'NULL' も使用されます。 See section 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 NULLIS NOT NULL 演算子と IFNULL() 関数を使用することができます。

カラム型の中には、NULL 値が特別に扱われるものがあります。テーブルの最初のカラム TIMESTAMPNULL を挿入すると、現在の日付と時刻が挿入されます。AUTO_INCREMENT カラムに NULL を挿入すると、順番の次の番号が挿入されます。

A.5.4 alias の問題

エイリアスを使用して、GROUP BYORDER 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 を実行して結果セットからどのレコードを使用するか決定します。

A.5.5 関連テーブルからのレコードの削除

MySQL では、サブクエリをサポートしていません(バージョン 4.1 より前)。また、DELETE ステートメントでの 2 つ以上のテーブルの使用もサポートしていません(バージョン 4.0 より前)。そのため、2 つの関連テーブルからレコードを削除するには、以下の方法を使用してください。

  1. メインテーブルで WHERE 条件に基づいて、レコードを SELECT する。
  2. 同じ条件に基づいて、メインテーブルのレコードを DELETE する。
  3. 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 節の引数の数に依存しません。

A.5.6 不整合レコードの問題解決

多くのテーブルが含まれる複雑なクエリを使用していて、それがレコードを返さない場合、以下の手順でクエリの問題を見つける必要があります。

  1. EXPLAIN でクエリをテストし、明らかに問題と思われる箇所があるか確認する。 See section 5.2.1 EXPLAIN 構文(SELECT に関する情報の取得)
  2. WHERE 節で使用されるフィールドだけを選択する。
  3. レコードが返るまで、クエリから 1 つ 1 つテーブルを削除する。 テーブルが大きい場合に有効なのは、クエリで LIMIT 10 を使用する方法である。
  4. クエリから最後に削除されたテーブルに対してレコードが一致したカラムに、 SELECT を実行する。
  5. FLOAT または DOUBLE カラムを小数と比較している場合、'=' は使用できない。浮動小数点の値は正確な値ではない。この問題は大部分のコンピュータ言語で共通。 たいていの場合、FLOATDOUBLE に変更すると問題は解決する。 See section A.5.7 浮動小数点比較の問題
  6. それでも問題が解決できない場合は、mysql test < query.sql で実行できる小さなテストを作成して、問題を表示する。 mysqldump --quick database tables > query.sql で、テストファイルを作成できる。エディタでファイルを開き、数が多ければいくつかの挿入行を削除する。そして、ファイルの最後に SELECT ステートメントを追加する。 まだ問題が残っているかどうか、以下の方法でテストしてください。
    shell> mysqladmin create test2
    shell> mysql test2 < query.sql
    
    mysqlbug を使用して、テストファイルを汎用 MySQL メーリングリストに投稿してください。 See section 1.7.1.1 MySQL メーリングリスト

A.5.7 浮動小数点比較の問題

浮動小数点数は、コンピュータアーキテクチャ内部では正確な値として格納されないため、混乱を引き起こす場合があります。通常画面に表示される値は、正確な値ではありません。

フィールドタイプ FLOATDOUBLE、および 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 |
+------+-------+-------+

A.6 オプティマイザ関連の問題

MySQL はオプティマイザを使用して、クエリを解決する最も優れた方法を見つけ出します。多くの場合、MySQL は最も可能性のあるクエリを見積もることができますが、場合によってはデータに関する十分な情報が手元にないので、経験に基づく '推測' を行う必要があります。

ここでは、MySQL が正しく理解しない場合を扱います。

MySQL が '正しく' 最適化するのに役立つツールは、以下のとおりです。

A.6.1 テーブルスキャンを回避する方法

MySQL がテーブルスキャンを使用してクエリを解決した場合、EXPLAIN では type カラム内に ALL が表示されます。これは、通常以下の場合に起こります。

大きなテーブルの '不正な' テーブルスキャンを回避するには、以下のことを行います。

A.7 テーブル定義関連の問題

A.7.1 ALTER TABLE の問題

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 は、以下のように動作します。

名前変更操作に何か問題が発生した場合は、MySQL は変更を取り消します。致命的な問題が発生した場合(もちろん起こってはならないことですが)、MySQL は旧テーブルを `B-xxx' のままにしておく可能性がありますが、システムレベルでの簡単な名前変更でデータは元に戻ります。

A.7.2 テーブルのカラム順序を変更する方法

SQL の主な目的は、データストレージから要求した情報を抽出することです。必ず、データを取り出す順序を指定する必要があります。たとえば、以下のようになります。

SELECT col_name1, col_name2, col_name3 FROM tbl_name;

上記は、col_name1col_name2col_name3 の順序でカラムを返します。

SELECT col_name1, col_name3, col_name2 FROM tbl_name;

上記の場合、col_name1col_name3col_name2 の順序でカラムを返します。

カラム順序は、以下のように変更できます。

  1. 正しい順序のカラムで新しいテーブルを作成する。
  2. INSERT INTO new_table SELECT fields-in-new_table-order FROM old_table を実行する。
  3. old_table を廃棄するか、名前変更する。
  4. ALTER TABLE new_table RENAME old_table

カラムを追加、移動、削除する場合、カラムが返される順序と位置が同じにならないので、アプリケーションで、SELECT * を使用してその位置に依存するカラムを絶対に取り出さないでください。データベース構造に簡単な変更を加えるだけでも、アプリケーションエラーが発生します。 もちろん SELECT * は、クエリのテストに最適です。

A.7.3 テンポラリテーブルの問題

以下、テンポラリテーブルの制限を示します。


Go to the first, previous, next, last section, table of contents.