一覧1000件の関連を1件ずつ引くと往復は1001回、802.8msかかりました。
まとめて引けば往復2回・3.6msです。返す行はどちらも同じで、差は往復だけから来ています。
索引が効いていても遅くなります。原因は探す時間ではなく、往復の回数です。
MySQLの索引が担うのは、探す部分です。マニュアルは索引は、特定の列の値を持つ行を素早く見つけるために使われると述べています。
探すのが速くても、問い合わせの回数が多ければ遅くなります。その分を数えました。
一覧を出したあと、各行の関連を引く場面です。返す行の数はどちらも同じにしてあります。
1往復 0.8ms、1行を返す手間 0.002ms として計算する 一覧の件数を変えて、1件ずつ引く場合とまとめて引く場合を比べる 一覧の件数 1件ずつ(往復) 1件ずつ(時間) まとめて(往復) まとめて(時間) 比 10件 11回 8.8ms 2回 1.6ms 5.4倍 50件 51回 40.9ms 2回 1.7ms 24.1倍 200件 201回 161.2ms 2回 2.0ms 80.6倍 1000件 1001回 802.8ms 2回 3.6ms 223.0倍
1000件では802.8msと3.6msです。223.0倍の差になります。
行を返す手間はどちらも同じ2.0msです。残りの800.8msはすべて往復でした。
10件では5.4倍にとどまります。試すときには気づきにくい差です。
比は件数にほぼ比例します。一覧が10件から1000件になれば、比も5.4倍から223.0倍へ広がります。
だから見るべきはその一覧が取りうる最大の件数です。平均ではありません。
返す行は同じ。差は往復の回数だけから来ている。
Indexes are used to find rows with specific column values quickly.原文MySQL 8.4 リファレンスマニュアル「How MySQL Uses Indexes」 この内容の有効期限2027-02-18
費用は行数に比例します。マニュアルも、表が大きいほど高くつくと明記しています。
MySQLで索引がない場合の動きは、マニュアルに明記されています。
索引がなければ、MySQLは最初の行から始めて、該当する行を見つけるために表の全体を読み通さなければならないという記述です。続けて「表が大きいほど、この費用は大きくなる」とも書かれています。
この比例のしかたは、PostgreSQLの記事で20万行を使って数えました。見に行く行は2万分の1、時間は203分の1でした。
比例するということは、試しに作った小さい表では差が出ないということでもあります。行が1000件なら、全部読んでも一瞬です。
索引の有無と、往復の回数は別の話です。両方が同時に効きます。
2番目が見つけにくいものです。1回ずつの問い合わせは速いので、記録を見ても遅い問い合わせとして出てきません。
見つけるには、1つの画面を出すのに何回問い合わせたかを数える必要があります。1回ごとの時間ではありません。
Without an index, MySQL must begin with the first row and then read through the entire table to find the relevant rows.原文MySQL 8.4 リファレンスマニュアル「How MySQL Uses Indexes」 この内容の有効期限2027-02-18
掛かる先が索引なので、同じ行を触っていなくても重なることがあります。
MySQLの行ロックは、行そのものに掛かるわけではありません。マニュアルはレコードロックとは、索引のレコードに対するロックであると定めています。
さらにギャップロックとは、索引レコードのあいだの隙間、あるいは最初の索引レコードの前や最後の索引レコードのあとの隙間に対するロックであるという種類もあります。
隙間に掛かるということは、まだ存在しない行の位置も押さえられるということです。重なる範囲が、行の数より広くなります。
重なった分は順番待ちになります。担当を増やしてどこまで縮むかを数えました。
処理 4000件。1件 2ms。同じ行を取り合う分は順番待ちになる 取り合う割合を変えて、担当を増やしたときの短縮を見る 取り合う割合 1人 2人 4人 8人 16人 16人での短縮 0% 8.00秒 4.00秒 2.00秒 1.00秒 0.50秒 16.0倍 5% 8.00秒 4.20秒 2.30秒 1.35秒 0.88秒 9.1倍 20% 8.00秒 4.80秒 3.20秒 2.40秒 2.00秒 4.0倍 50% 8.00秒 6.00秒 5.00秒 4.50秒 4.25秒 1.9倍
5%重なるだけで、16人での短縮は9.1倍に落ちます。16.0倍から半分近くです。
20%なら4.0倍です。担当を4人から16人にしても、3.20秒が2.00秒にしかなりません。
2番目が要注意です。索引がなければ全部の行を走査するので、その分だけ掛かる範囲が広がります。
つまり索引は、読みを速くするだけではありません。取り合う範囲を狭めるほうでも効きます。
実在のデータベースは使わず、往復と待ちを式で置いて計算しています。1往復0.8msという値も、同じ機械の中なら小さくなり、別の場所にあれば大きくなります。取り合いの計算も、重なった分は同時に1人しか進めないという単純な形に置きました。実際にはロックの種類によって、読みは通るが書きは待つといった中間があります。ここで見せているのは、返す行が同じでも往復の回数で時間が桁で変わること、少しの重なりが並列の効きを大きく削ることの2つです。
A record lock is a lock on an index record.原文MySQL 8.4 リファレンスマニュアル「InnoDB Locking」 この内容の有効期限2027-02-18
同じ課題を持つ会社にとって、動いている設定は「作る時間」を買えるということです。ServiceDockは自作のワークフローやテンプレートを出品できるマーケットプレイスです。手数料や出品の流れは出品者向けページにまとまっています。
出品の仕組みを見る