3

トランザクションをサポートするために、先週、1 つのプロジェクトのすべての MySQL テーブルを MyISAM から InnoDB に移行しました。これには のコマンドを使用しalter tableました。

ほとんどは正常に動作しますが、特定のクエリの実行が非常に遅く、常にエラーが発生しますIncorrect key file for table '/tmp/#sql_xxxx_x.MYI

user後で、問題をテーブルとテーブルの 2 つのテーブルの内部結合に絞り込みましたagreementuserそして、(ie ) の外部キー フィールドと(ie )agreement_idの主キー フィールドの間で内部結合が行われました。agreementid

userテーブルには 50,000 行のデータしかありませんが、テーブルagreementには 1 行しかありません。そして、ユーザーのインデックスを設定しましたagreement_id

いずれにせよ、これは非常に軽量なクエリのように見えますが、ボトルネック全体であることが判明しました。

の完全なスキーマは次のagreementとおりです。

CREATE TABLE IF NOT EXISTS `agreement` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `remark` varchar(200) NOT NULL,
  `content` longtext NOT NULL,
  `is_active` tinyint(1) NOT NULL,
  `date_stamp` datetime NOT NULL,
  PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;

私が疑問に思っていることの 1 つは、テーブルremark内の longtext フィールドですagreementが、内部結合にフィールドを使用していません。実際、remarkクエリ結果で選択しなくても、クエリは遅くなります。

最後に、 の表をagreementからinnoDBに戻しMyISAM、すべてが正常になるようにしました。クエリは 1 秒未満で終了します。

さて、私の質問は、実際にここで何が起こっているのでしょうか? innoDB テーブルにテキスト フィールドが含まれると、テーブルを内部結合に使用できなくなるということですか?

将来同じ問題を回避できるように、本当の理由を知ることができればいいのにと思います。

どうもありがとう。

4

4 に答える 4

2

これは有名でトリッキーなものです。最も可能性の高い原因は、/tmpのスペースが不足していることです。

これがあなたを助けるかもしれない私のブックマークに保持しているリンクです:http ://www.mysqlperformancetuning.com/a-fix-for-incorrect-key-file-for-table-mysql

私の経験では、限られていますが、このエラーメッセージが表示される主な理由は、tmpdirの容量が不足しているためです。私のように、1Gb、2Gb、4Gbの空き容量を確認します。十分ではないかもしれません。そしてその理由は次のとおりです。MySQLは数秒でそれよりも大きな一時テーブルを作成し、空きスペースをすぐに埋めることができます。クエリの性質とデータベースのサイズに応じて自然に。

テーブルで修理を試すこともできますが、私にとってはブレイクダンスと同じくらい便利です:/

于 2012-06-20T11:53:02.403 に答える
1

クエリの目的は何ですか? あなたのコメントから、あなたはユーザー情報をリストしているだけであり、同意からは何も記載されていないことがわかりました。エンジン間で変換しているので、制約を追加する前にクリーンアップを行っていると思います。その場合は、代わりに次のようなユーザー テーブルからの左結合を検討してください。

select user.* from user left join agreement on user.agreement_id = agreement.id where user.agreement_id != 0;

クリーンアップではなく、単に同意のあるユーザーを探すだけの場合は、シンプルにします

select user.* from user where user.agreement_id != 0;

目的がそれ以外の場合は、速度のために内部結合で必要になる可能性があるため、user.agreement_id にインデックスを追加することを検討してください。本当の目的をお知らせください。より良いサポートが得られる可能性があります。

于 2012-06-26T14:36:37.013 に答える
1

InnoDB には、バッファ サイズなどの独自の設定があります。それを確認して、調整できる場合は先に進んでください。テストのために、それらを2倍にしてみてください。それが役立つ場合は、最適化することをお勧めします。それは大きな違いを生む可能性があります。

役立つリンク:

http://www.mysqlperformanceblog.com/2007/11/03/choosing-innodb_buffer_pool_size/

http://dev.mysql.com/doc/refman/5.5/en/innodb-buffer-pool.html

于 2012-06-25T15:40:38.800 に答える
1

ここでの問題は、remarkフィールドが次のように定義されている可能性がありvarchar(200)ます。一時テーブルとメモリ テーブルvarcharは固定長で格納されることに注意してください。したがって、50k 行varchar(200)は、すべてが空であっても大量のメモリを消費する可能性があります。

これが問題である場合は、いくつかの方法のいずれかを試すことができます。

  • 列に値を持つ行がほとんどない場合はvarchar(200)、NULL が許可された列を作成し、空の文字列の代わりに常に NULL 値を使用します。
  • テキストに変更varchar(200)します(もちろん欠点があります-常にディスク上の一時テーブルを使用します)
  • 200文字はいらないかも?小さいVARCHARサイズを使用してみてください
  • tmp_table_size と max_heap_table_size を調整して、メモリ内のより大きな一時テーブルを処理できるようにしてくださいhttp://dev.mysql.com/doc/refman/5.1/en/internal-temporary-tables.html
  • メモリテーブルの動的行フォーマットをサポートしているため、percona サーバーを使用してください http://www.mysqlperformanceblog.com/2011/09/06/dynamic-row-format-for-memory-tables/
于 2012-06-25T17:05:27.860 に答える