MyISAM
は単純なテーブル用であり、InnoDB
よりもアーキテクチャが速いため、選択すると思いました。したがって、このテーブルのエンジンをInnoDB
からMyISAM
に変更しました。
CREATE TABLE `table1` (
`DateTime` datetime NOT NULL,
`BidHigh` decimal(11,5) NOT NULL,
`BidLow` decimal(11,5) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin COMMENT='1 minute rates';
ALTER TABLE `table1` ADD PRIMARY KEY (`DateTime`);
これらの条件が適用されます:
実行時間:
InnoDB
エンジンを使用すると、スクリプトは199秒実行されます。MyISAM
エンジンを使用すると、スクリプトは1'026秒実行されます。 5倍以上長い。これらのSELECTステートメントを実行しています:
SELECT `DateTime` FROM table1
WHERE `DateTime` BETWEEN '2018-12-27 07:50:00' AND '2199-12-31 23:59:00'
AND BidHigh > 0.96604
ORDER BY `DateTime` LIMIT 1;
-および-
SELECT MIN( BidLow ) FROM table1
WHERE `DateTime` BETWEEN '2018-12-27 07:45:00' AND '2199-12-31 23:59:00';
OK、インデックスの問題だとわかりました。これら2つのインデックスを追加する
ALTER TABLE `table1` ADD UNIQUE `BidHigh` (`DateTime`, `BidHigh`);
-および-
ALTER TABLE `table1` ADD UNIQUE `BidLow` (`DateTime`, `BidLow`);
パフォーマンスの問題を修正し、スクリプトは245秒を必要としますが、それでもInnoDB
よりも遅くなります-これは本当に私が期待したものではありません...
これらのインデックスをInnoDB
バージョンに追加しても、パフォーマンスは向上しません。
私の質問:
InnoDB
はこれらのインデックスを必要とせず、さらに高速なのですか?MyISAM
への変更がこのような恐ろしいパフォーマンスを引き起こしたと私がどう考えているかを完全に誤解していました。1)InnoDBもインデックスを使用すると高速になります。
2)適切なインデックス付けを備えたInnoDBが最良のソリューションです。
3)MyISAMは、10年以上もの間、ほとんどのワークロードでInnoDBよりも低速でした。 2つの間でメモリとキャッシングの動作に基本的な違いがあります。
この場合、InnoDBは主キーによって最初の行を選択していました。 InnoDBテーブルは主キーによってクラスター化されているため、これは非常に高速であり、PKはテーブルを作成したときからすでにメモリ内にある可能性があります。
BidHighでインデックスを作成すると、さらに高速になります。
MyISAMを使用する圧倒的な理由がない限り、使用しないでください。そして、あなたが圧倒的に良い理由があると思うなら、それらは2020年にはほとんどないのでそれを再調査する必要があります。
「MyISAMの方がいい...」は、非常に古くなっている古い「妻の物語」です。 InnoDBを使用します。
2つのエンジンはまったく異なる方法でインデックスを使用します。
PRIMARY KEY(DateTime
)-同じ秒の2つのレコードを保存しないでください。 PKは固有です。
クエリ1
_SELECT `DateTime` FROM table1
WHERE `DateTime` BETWEEN '2018-12-27 07:50:00' AND '2199-12-31 23:59:00'
AND BidHigh > 0.96604
ORDER BY `DateTime` LIMIT 1;
_
これには2つの範囲が含まれるため、MyISAMまたはInnoDBのどちらにも適切なインデックスを構築することは基本的に不可能です。オプティマイザーはDateTime
で始まるインデックスを使用し、他の列のすべての行をテストします。可能なインデックスを調べてみましょう:
_PRIMARY KEY(DateTime)
_
MyISAMの場合、DateTimeに基づくBTreeと、データ行へのポインターがあります。データ行を調べてBidHigh
を取得し、その値を確認します。
InnoDBの場合、データは日時順に並べられます。したがって、BidHighを取得するための追加はありません。勝者:InnoDB。
どちらのエンジンでも、オプティマイザーmightは、ソートを回避してLIMIT
に到達するのに十分スマートです。ただし、テストする必要がある行数に依存するため、これは危険です。このデータの変動により、選択したクエリプランにより、5倍(または500倍)のスローダウンが容易に発生する可能性があります。 INDEX(DateTime、BidHigh)
これはMyISAMを「カバーする」インデックスにすることで、MyISAMの非効率性を解決します。 InnoDBにとって、それはほとんど無駄です。 PKは基本的にINDEX(DateTime, BidHigh, BidLow)
であり、2列のインデックスよりもわずかに悪いだけです。
_INDEX(BidHigh, DateTime)
_
これはおそらく高速ですifBidHignの範囲テストに一致する行がlot少ない場合、DateTimeの範囲テストよりも少なくなります。しかし、LIMIT
に到達する前に並べ替えが存在します。
_EXPLAIN SELECT ...
_を使用して、何が行われたかを確認します。
たぶん空間
最初のクエリには2Dインデックスが必要ですが、これはINDEX
が提供するものではありません。 「緯度/経度」という用語で表現された5つのオプションについて説明します。 http://mysql.rjweb.org/doc.php/find_nearest_in_mysql
SPATIAL
の使用は、最初のクエリでは実行可能かもしれませんが、2番目のクエリでは実行できない可能性があります。
クエリ2
_SELECT MIN( BidLow ) FROM table1
WHERE `DateTime` BETWEEN '2018-12-27 07:45:00' AND '2199-12-31 23:59:00';
_
InnoDBの場合:PRIMARY KEY(DateTime)
は、約1年分のデータのスキャンにつながります。
MyISAMの場合、正確にINDEX(DateTime, BidLow)
でない限り、インデックスを使用することはできません。
23:59:00
その日の最後の1分間に入札を想定していませんか?
使用を検討してください
_WHERE DateTime >= '...
AND DateTime < '...-01-01'
_
コメントフィールドの長さが十分でないため、コメントを回答として追加しています。
私は Gordan Bobic の回答を受け入れました。彼は新しいメンバーなので、彼の回答を受け入れることで得られる評判はpushingだと思います。
彼の発言の一部が Rick James の回答で確認されたので、それは私に示しています Gordan Bobic は何が起こっているのかを理解しています。
ゴーダンの発言:
MyISAMを使用する圧倒的に正当な理由がない限り、使用しないでください。そして、もしあなたが圧倒的に良い理由があると思うなら、それらは2020年にはほとんどないのでそれを再調査する必要があります。
自分の理解が間違っていることに気づき、使用したエンジンに関して自分でresetしなければならなかったので、私にとって非常に重要なトリガーでした。
1つの質問に当てはまらないため、問題全体については触れませんでした。両方の回答を読んだ後、データベースを再構築する必要があることに気付きました。したがって、たとえば、いくつかのJSON
テーブルにInnoDB
フィールド[最大長は〜6kバイト、平均長は〜2kバイト]がありました。
行数が多いため、これらのInnoDB
テーブルのサイズも大きく、毎日増加していました。これが、これらのInnoDB
テーブルをMyISAM
に変換し始めた理由です。しかし、前述のとおり、これによりパフォーマンスが大幅に低下したため、この質問をしました。
これらのJSON
fieldsを、2つのフィールド(主キーとMyISAM
フィールド]のみを持つ非常に単純なJSON
テーブルに抽出しました。これによりサイズが小さくなり[〜30%]、パフォーマンスに影響を与えません。
多分私は今少し混乱しているように聞こえるかもしれませんが、全体的な文脈でそれは私を大いに助け、問題を解決しました!