2011-02-10 2 views
2

私はInnoDBとMEMORYバージョンのテーブルを持っています。両方とも同じ索引と同じ30,000行のデータを持ちます。 MEMORYテーブルに対して実行すると非常に遅く実行される特定のクエリがあります。ここで なぜMEMORYテーブルのこのクエリはInnoDBのツインよりも遅いのですか?

は、InnoDBは反対だ:

SELECT emails.id 
FROM emails 
LEFT JOIN custom_data_person pd1 ON (pd1.person_id = emails.person_id) 
WHERE pd1.field_id = 13 

2928 rows in set (0.24 sec) 

*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: pd1 
     type: ref 
possible_keys: person_id,field_id 
      key: field_id 
     key_len: 5 
      ref: const 
     rows: 20240 
     Extra: Using where; Using index 
*************************** 2. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: emails 
     type: ref 
possible_keys: person_id 
      key: person_id 
     key_len: 4 
      ref: test.pd1.person_id 
     rows: 1 
     Extra: Using index 

ここでのメモリ:

SELECT emails.id 
FROM emails_memory AS emails 
LEFT JOIN custom_data_person pd1 ON (pd1.person_id = emails.person_id) 
WHERE pd1.field_id = 13 

2928 rows in set (1.40 sec) 

*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: emails 
     type: ALL 
possible_keys: person_id 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 30000 
     Extra: 
*************************** 2. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: pd1 
     type: ref 
possible_keys: person_id,field_id 
      key: person_id 
     key_len: 10 
      ref: test.emails.person_id,const 
     rows: 1 
     Extra: Using where; Using index 

(私はデフォルトのハッシュインデックスと同じしようとした結果が得られたPERSON_IDインデックスはBTREEインデックスであることに注意してください。同じように)

だから、MySQLは2番目のクエリを別の方法で最適化してパフォーマンスを悪化させるようです。何故ですか?それを "修正"することはできますか?

+0

2つのテーブルで 'explain tablename'と' show indexes from tablename'を実行できますか? 2つの異なるエンジンが異なるように最適化するため、エンジンにヒントを提供する必要があります。 – DeveloperChris

答えて

2

あなたは本当に気にしません。 30,000行の小さなテーブルでは、テーブルスキャンの場合でも、何かが非常に高速になります。

ただし、別の説明計画が選択されているようです。 innodbの場合、まずcustom_data_personテーブルを使用し、カバリングインデックスを使用します。次に、custom_data_personテーブルにある各行の電子メールテーブルを照会します。これはまじめな説明計画のようです。

メモリテーブルのオプティマイザでは、おそらく悪い評価があります。

私はメモリテーブルをクリアします。メモリテーブルのように動作するテーブルが必要な場合は、MyISAMテーブルを使用し、サーバの起動時にそのテーブルを切り捨てます。メモリテーブルは、最大長にパッディングされたvarcharsを格納するため、非常に悪いです。通常、他のタイプのテーブルよりも多くのメモリを使用します。 MyISAMはストレージを非常に効率的に使用します。あるいは、InnoDBテーブルをすべて使用してください。

残念ながら、innodbはテーブル単位で耐久性を設定する方法を提供していないので、各トランザクションのfsyncがあなたを煩わせる場合は、より大きなトランザクションを実行する必要があります。

いくつかのエンジンを使用することは妥協です。サーバーが自動的にエンジン間で(有限の)ラムを分割することはほとんどありません。したがって、通常は1つのエンジンだけを使用したいと考えています。これにはメモリエンジンが含まれています。このメモリエンジンは、あなたのinnodbからメモリのヒープを取り除きます(したがって、あなたがそのように構成すればメモリ内のDBが少なくて済みます)。

本当に、実際には、本当に30k行は気にしません。たとえ広大であっても、30k行は最小のメモリに収まる。 30k行を使用すると、どのエンジンもメモリエンジンになります。

+1

メモリテーブルを使用する理由は完全に正当です。 – DeveloperChris

+0

私は彼らが何であるか全く理解していません。 – MarkR

+1

ストアドプロシージャ内のテンポラリテーブルのヒープはより良いです。INNODBテーブルの場合、 "create table"が完了するまでには1/2秒かかると思われます。また、BIGテーブルの行の1/2を削除すると(たとえば、1,000,000行)、時間がかかります。それは私にとっては定期的に行うために実際に必要なばかげて聞こえます。いくつかのエンジンを使用することについてのあなたのコメント - パフォーマンスが低下しますか?あなたは記憶を言います(私はそれを得ます)が、InnodbテーブルをMyISAMテーブルに結合することは、そのようなものに対してはペナルティがありますか? –

関連する問題