先日の日記を書くために色々試している最中、あまりにも潔く mysql クライアントコマンドがさくっと落ちるので、発生条件を調べてみました。原因の特定には至っていません。
起こっていること
Windows 10 のMySQLにて、mysql> プロンプトが出ているところで、単純なSELECT文を叩くと、無言で mysql があっさり落ちる。
mysql> SELECT * FROM n03_20_200101 WHERE RECID<20; D:\>
使用データ
先日の日記に書いた方法で取り込んだ「全国」のデータ(千葉県ではなく全国)の入ったテーブルを使って再現させることができます。ふつうに blob に放り込んだ値を HEX() 取ったりしても再現できるかもしれません。あ、blob である必要すらなくて、varchar とか text とかでも良さそう。
発生条件
どうやら、結果セットに含まれるカラム値の サイズまたは行のサイズが大きすぎるときに落ちる気がする。
mysql> SELECT RECID, LENGTH(HEX(SHAPE)),LENGTH(ST_AsText(SHAPE)) FROM n03_20_200101 WHERE RECID<20; +-------+--------------------+--------------------------+ | RECID | LENGTH(HEX(SHAPE)) | LENGTH(ST_AsText(SHAPE)) | +-------+--------------------+--------------------------+ | 0 | 57826 | 55812 | | 1 | 57634 | 55409 | | 2 | 27394 | 26233 | | 3 | 25666 | 24674 | | 4 | 47362 | 45461 | | 5 | 162210 | 156154 | | 6 | 52898 | 50970 | | 7 | 22178 | 21460 | | 8 | 35874 | 34414 | | 9 | 56194 | 54322 | | 10 | 1154 | 1079 | | 11 | 386 | 344 | | 12 | 642 | 582 | (略)
という情報を元に、RECID=5 の行のみを抽出してみる。
mysql> SELECT RECID, LENGTH(SHAPE), ST_AsText(SHAPE) FROM n03_20_200101 WHERE RECID=5; D:\>
うん、落ちた。AsTextとかよくわかんないという人は、代わりに HEX(SHAPE)でも良いです。
閾値はどこに
試行錯誤で範囲を絞ったので、以下のクエリで閾値捜索の最後のツメを。
SELECT RECID, LENGTH(SHAPE) a, LENGTH(ST_AsText(SHAPE)) b FROM n03_20_200101 WHERE LENGTH(ST_AsText(SHAPE)) >101296 AND LENGTH(ST_AsText(SHAPE))<101719 ORDER BY b ; +--------+-------+--------+ | RECID | a | b | +--------+-------+--------+ | 99545 | 54305 | 101297 | | 31451 | 53921 | 101297 | | 59657 | 54225 | 101307 |OK | 33266 | 53905 | 101361 |OK | 48032 | 54049 | 101376 |NG | 32203 | 54245 | 101437 | | 11066 | 53301 | 101528 | | 115488 | 49233 | 101718 | +--------+-------+--------+ 8 rows in set (28.52 sec)
SELECT RECID, LENGTH(SHAPE), ST_AsText(SHAPE) FROM n03_20_200101 WHERE RECID=33266; --OK SELECT RECID, LENGTH(SHAPE), ST_AsText(SHAPE) FROM n03_20_200101 WHERE RECID=48032; --NG
1文字ずつくわえて見ると RECID=33266 は1文字でも加えたら、もうアウト。
SELECT RECID, LENGTH(SHAPE), CONCAT(ST_AsText(SHAPE),"X") FROM n03_20_200101 WHERE RECID=59657; --OK SELECT RECID, LENGTH(SHAPE), CONCAT(ST_AsText(SHAPE),"X") FROM n03_20_200101 WHERE RECID=33266; --NG
もしかして、出力カラムのサイズではなくレコードサイズなのでは?と 余計な取得列を少しずつ削って見ると、アタリ。他の列をすべて取得やめてみた結果が以下のもの。
SELECT CONCAT(ST_AsText(SHAPE),"XXXXX") FROM n03_20_200101 WHERE RECID=33266; //OK SELECT CONCAT(ST_AsText(SHAPE),"XXXXXX") FROM n03_20_200101 WHERE RECID=33266; //NG
101361+5= 101366 byte まではOK、 101367バイトがNGと推測できそうです。
環境
Windows 10 上に、MySQL Installer を使ってインストールしたもの。サーバは utf8mb4、
クライアントは cp932 でも utfmb4 でも発生。
mysql> status -------------- mysql Ver 8.0.22 for Win64 on x86_64 (MySQL Community Server - GPL) Connection id: 30 Current database: shptest Current user: root@localhost SSL: Cipher in use is TLS_AES_256_GCM_SHA384 Using delimiter: ; Server version: 8.0.22 MySQL Community Server - GPL Protocol version: 10 Connection: localhost via TCP/IP Server characterset: utf8mb4 Db characterset: utf8mb4 Client characterset: cp932 Conn. characterset: cp932 TCP port: 3306 Binary data as: Hexadecimal Uptime: 3 hours 35 min 55 sec Threads: 4 Questions: 117 Slow queries: 8 Opens: 190 Flush tables: 3 Open tables: 111 Queries per second avg: 0.009
mysql> status -------------- C:\Program Files\MySQL\MySQL Server 8.0\bin\mysql.exe Ver 8.0.22 for Win64 on x86_64 (MySQL Community Server - GPL) Connection id: 29 Current database: shptest Current user: root@localhost SSL: Cipher in use is TLS_AES_256_GCM_SHA384 Using delimiter: ; Server version: 8.0.22 MySQL Community Server - GPL Protocol version: 10 Connection: localhost via TCP/IP Server characterset: utf8mb4 Db characterset: utf8mb4 Client characterset: utf8mb4 Conn. characterset: utf8mb4 TCP port: 3306 Binary data as: Hexadecimal Uptime: 3 hours 35 min 21 sec Threads: 3 Questions: 113 Slow queries: 8 Opens: 190 Flush tables: 3 Open tables: 111 Queries per second avg: 0.008
結局分からず仕舞い
現時点では Linux での動作を試していないので、これが Windows固有の現象なのか OS問わず発生するものなのか、分かりません。また、サーバのエラーログには記録なしで、一切の調査の足がかりがないのが、なかなか辛いですね。 まぁ、許容サイズを超えてエラーになるのはまだしも、ストンと落ちてしまう(接続が切れてしまう)のはいただけないなぁというのが私の感覚です。
mysql params でざっと見てみた感じでは、それっぽい制限値はなさそうで、もにゃもにゃした気分です。
variable / MySQL Parameters
これ、なんなんですかね。
その晩の追記
その後いろいろ試してみたら、とりあえず上で書いた「閾値」候補は、一旦とりさげ。
例えばこれ、
SELECT RECID, LENGTH(SHAPE), ST_AsText(SHAPE) FROM n03_20_200101 WHERE RECID=33266; --OK SELECT RECID, LENGTH(SHAPE), ST_AsText(SHAPE) FROM n03_20_200101 WHERE RECID=48032; --NG
実行順序を逆にしたら、NGだったやつは通って、OKだったやつがダメになりました。もう少し再現性ある内容を書く前に、yoku0825さんが試してくれたものを紹介すると、これだけで落ちるらしい。
なんとこれだけで落ちたウインドーズ版zip
— yoku0825 (@yoku0825) 2020年12月22日
mysql> SELECT REPEAT('a', 1000000);
PS C:\Users\yoku0825\Downloads\mysql-8.0.22-winx64\mysql-8.0.22-winx64>
mysql> SELECT repeat('a', 101367); (結果が表示される) mysql> SELECT 'a'; D:\>
「次のクエリをダメにするクエリ」みたいなのがあるっぽいと考えたほうがいいのかも?
もちょっと追記。「次のクエリをダメにするクエリ」という観点で試してみたら、こんな落とし方もあります、
mysql> SELECT repeat('a', 100000); (結果が表示される) mysql> STATUS D:\>