Blog | ytyng.comhttps://b.ytyng.com/blog/2024-03-28T09:28:02+00:00BlogMySQL で 2027 Malformed packet エラーが出る場合の解決ヒント2022-09-11T09:58:30+00:002024-03-27T14:07:37+00:00ytynghttps://b.ytyng.com/blog/author/ytyng/https://b.ytyng.com/blog/django-mysql-client-2027-malformed-packet-error/<h2>概要</h2>
<p>Django で 生SQL を発行する際、特定の SQL で</p>
<pre> File "<my-project>/.venv/lib/python3.9/site-packages/MySQLdb/connections.py", line 259, in query<br/> _mysql.connection.query(self, query)<br/>django.db.utils.OperationalError: (2027, 'Malformed packet')</pre>
<p>が発生した。</p>
<h2>環境</h2>
<pre><span>django </span>= <span>"==3.2.15"<br/>mysqlclient = "==2.0.3" (2.1.1でも発生するのを確認した)<br/></span></pre>
<h2>再現コード</h2>
<p>発生するコードは次のようなもの</p>
<pre>with connections['default'].cursor() as cursor:<br/> sql = """SELECT status_id FROM order_status<br/>WHERE order_status_name IN ("入金済み", "完了")"""<br/> cursor.execute(sql)<br/> print(cursor.fetchall())</pre>
<p>この時、<strong>この SQL は結果が期待どおりではないものの完了し、次のSQL の発行時に</strong></p>
<pre>django.db.utils.OperationalError: (2027, 'Malformed packet')</pre>
<p>このエラーが発生する。</p>
<h2>解決方法</h2>
<pre>SELECT status_id FROM order_status<br/>WHERE order_status_name IN ("入金済み", "完了")</pre>
<p>この SQL 文で</p>
<pre>order_status\nWHERE</pre>
<p>となっている箇所の、改行の前後どちらかに半角スペースを入れるか、</p>
<pre>"入金済み", "完了"</pre>
<p>このダブルクォーテーションを<strong>シングルクオーテーションに変える</strong>。それで発生しなくなる。</p>
<p>MySQL では、ダブルクオーテーションは避けたほうが良い。</p>Django で 2013, 'Lost connection to MySQL server during query' が出たので NO_ENGINE_SUBSTITUTION を無くした2021-11-14T11:10:12+00:002024-03-25T20:25:50+00:00ytynghttps://b.ytyng.com/blog/author/ytyng/https://b.ytyng.com/blog/mysql-django-no-engine-substitution/<p>Django で、MySQL (5.7) にクエリを出す時</p>
<pre>(2013, 'Lost connection to MySQL server during query')</pre>
<p><br/>のエラーが出て、処理が停止するようになった。</p>
<p><br/>まず、接続中の コネクションで、 innodb_strict_mode を見てみる</p>
<pre><span>SHOW VARIABLES LIKE </span><span>'%innodb_strict_mode%'</span>;</pre>
<p>ON である必要がある。</p>
<p><a href="https://django-mysql.readthedocs.io/en/latest/checks.html#django-mysql-w002-innodb-strict-mode">https://django-mysql.readthedocs.io/en/latest/checks.html#django-mysql-w002-innodb-strict-mode</a></p>
<p>これは 既にONになっていた。</p>
<p>次に、sql_mode を確認する。</p>
<pre><span>SELECT </span><span>@@SESSION.sql_mode</span>;</pre>
<pre><span>STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION</span></pre>
<p>MySQL サーバの、NO_ENGINE_SUBSTITUTION を外して再起動</p>
<p></p>
<pre>STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER</pre>
<p>この問題は出なくなった</p>MySQL 8.0 で SSL モードを無効にして接続する (ERROR 2026 (HY000): SSL connection error: error 対応)2021-01-01T12:28:03+00:002024-03-28T09:28:02+00:00ytynghttps://b.ytyng.com/blog/author/ytyng/https://b.ytyng.com/blog/mysql-error-2026-hy000-ssl-connection-error/<p>Mysql Client 8.0 から、MySQL 5.6 に接続しようとした所、</p>
<p>DataGrip では</p>
<pre>[08S01]<br/>Communications link failure<br/><br/>The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.<br/>java.io.EOFException: SSL peer shut down incorrectly.</pre>
<p>というメッセージが表示され、コマンドラインでは</p>
<pre>% mysql --host=xxxxx --user=xxxxx --password<br/>Enter password:<br/>ERROR 2026 (HY000): SSL connection error: error:1408F10B:SSL routines:ssl3_get_record:wrong version number</pre>
<p>というエラーとなった。</p>
<p>これは、もともとサーバ側が SSL 無効でサービスしているにもかかわらず、クライアントからは SSL を有効にして接続を試みて、失敗している。</p>
<p></p>
<p>もしかしたら、クライアント側の SSL のバージョンと、サーバ側で対応している SSL の暗号化方式の不一致で発生しているかもしれない。</p>
<p>ちなみに、クライアント側 Mac の OpenSSL はこれ</p>
<pre>% openssl version<br/>LibreSSL 2.8.3</pre>
<p></p>
<p>単純に、SSL を使わないで平文で良いなら、</p>
<p>mysql コマンドの場合は <code>--ssl-mode=DISABLED</code> をつける。</p>
<pre>% mysql --host=xxxxx --user=xxxxx --password --ssl-mode=DISABLED<br/>Enter password:<br/>Welcome to the MySQL monitor. Commands end with ; or \g.<br/>Your MySQL connection id is 1693381<br/>Server version: 5.6.34-log MySQL Community Server (GPL)</pre>
<p></p>
<p>DataGrip の場合は、接続設定の Advanced タブの中に、<code>useSSL</code> という設定項目があるので、これを <code>FALSE</code> に変更する。</p>
<p><img alt="" src="https://www.ytyng.com/media/uploads/mysql-ssl/data_sources_and_drivers.png"/></p>
<p></p>mysql django.db.utils.InterfaceError: (0, '')2020-11-08T10:53:38+00:002024-03-27T04:19:37+00:00ytynghttps://b.ytyng.com/blog/author/ytyng/https://b.ytyng.com/blog/mysql-djangodbutilsinterfaceerror-0/<pre>django.db.utils.InterfaceError: "(0, '')"</pre>
<p></p>
<p>が出る場合</p>
<p></p>
<p>テーブルやレコードによって、get時にこのエラーが出たり出なかったりする場合は、接続文字コードが合ってないかもしれない。</p>
<p></p>
<p><span style="text-decoration: line-through;">もし、utf8 で接続しているなら、一度 utf8mb4 にして様子を見てみる。</span></p>
<pre><span style="text-decoration: line-through;">DATABASES = {</span><br/><span style="text-decoration: line-through;"> "default": {</span><br/><span style="text-decoration: line-through;"> "ENGINE": "django.db.backends.mysql",</span><br/><span style="text-decoration: line-through;"> "NAME": "....",</span><br/><span style="text-decoration: line-through;"> "USER": "....",</span><br/><span style="text-decoration: line-through;"> "PASSWORD": "....",</span><br/><span style="text-decoration: line-through;"> "HOST": "....",</span><br/><span style="text-decoration: line-through;"> "PORT": "",</span><br/><span style="text-decoration: line-through;"> "OPTIONS": {</span><br/><span style="text-decoration: line-through;"> "charset": "utf8mb4"</span><br/><span style="text-decoration: line-through;"> },</span><br/><span style="text-decoration: line-through;"><span style="text-decoration: underline;"><br/></span></span></pre>
<p>2021-08-07 追記<span style="text-decoration: line-through;"><span style="text-decoration: underline;"><br/></span></span></p>
<p><a href="https://www.ytyng.com/blog/mysql-80-client-django-character-set-latin1-utf8mb4/">MySQL 8.0 のクライアントで MySQL 5.7 サーバに接続すると Charset の指定がクライアントからできない</a></p>
<p>で書いたが、mysql のクライアントが 8.0 相当で、サーバが5.7 の場合、文字コードの指定がクライアント側からできない。</p>
<p>なので、文字コードについては、「サーバ側で指定して<strong>クライアントからは指定しない</strong>」</p>
<p>(DATABASES の <strong>OPTIONS を指定しない</strong>) というのが、一番良いと考えている。</p>
<p></p>
<p></p>
<p></p>
<p><span style="text-decoration: line-through;"><span style="text-decoration: underline;"></span></span></p>
<p><span style="text-decoration: line-through;"><span style="text-decoration: underline;"></span></span></p>Python(Django) で NameError: name '_mysql' is not defined となる場合 (特にローカル開発中)2020-10-11T02:52:50+00:002024-03-28T03:36:47+00:00ytynghttps://b.ytyng.com/blog/author/ytyng/https://b.ytyng.com/blog/python-name-error-mysql-_mysql-is-not-defined/<p class="p1">今まで動いていた<span class="s1"> Django </span>プロジェクトを、久しぶりに起動したら</p>
<p class="p1"></p>
<pre class="p1">version_info, _mysql.version_info, _mysql.__file__<br/>NameError: name '_mysql' is not defined</pre>
<p class="p1">というエラーが出て起動しなかった場合。</p>
<p class="p1"></p>
<p class="p1">Python プロジェクト外の、MySQL のライブラリが更新されたことで、プロジェクト内の mysqlclient からのリンクが切れている。</p>
<p class="p1">おそらく、 brew install mysql-client などしたことによるもの。</p>
<p class="p1"></p>
<p class="p3"><span class="s1">mysqlclient </span>の再インストールで解消できる。</p>
<p class="p3"></p>
<pre class="p1">pip install --force-reinstall mysqlclient</pre>MySQL で、 root から WITH GRANT OPTION 権限が消えたので2018-02-26T13:14:58+00:002024-03-28T01:51:57+00:00ytynghttps://b.ytyng.com/blog/author/ytyng/https://b.ytyng.com/blog/mysql-missing-with-grant-option-for-root/<p>Ansible の mysql_user モジュールで、root ユーザーを操作していたら、他のユーザーに権限付与ができなくなっていた。</p>
<p></p>
<p>root の show grants 見たら</p>
<pre>mysql> show grants;<br/>+--------------------------------------------------------------+<br/>| Grants for root@localhost |<br/>+--------------------------------------------------------------+<br/>| GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' |<br/>| GRANT PROXY ON ''@'' TO 'root'@'localhost' WITH GRANT OPTION |<br/>+--------------------------------------------------------------+</pre>
<p>WITH GRANT OPTION が消えていた。</p>
<p></p>
<p>その場合、</p>
<pre style="background-color: #ffffff; color: #000000; font-family: 'Menlo'; font-size: 9.0pt;"><span style="color: #000080; font-weight: bold;">UPDATE </span>mysql.user <span style="color: #000080; font-weight: bold;">SET </span><span style="color: #660e7a; font-weight: bold;">Grant_priv </span>= <span style="color: #008000; font-weight: bold;">'Y' </span><span style="color: #000080; font-weight: bold;">WHERE </span><span style="color: #660e7a; font-weight: bold;">User</span>=<span style="color: #008000; font-weight: bold;">'root'</span>;</pre>
<p>して、強制的に Grant_priv を立てるといい。</p>
<p>(この後、FLUSH PRIVILEGES; いるかも?)</p>
<p></p>
<p>正しい show grants は</p>
<pre>mysql> show grants;<br/>+---------------------------------------------------------------------+<br/>| Grants for root@localhost |<br/>+---------------------------------------------------------------------+<br/>| GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION |<br/>| GRANT PROXY ON ''@'' TO 'root'@'localhost' WITH GRANT OPTION |<br/>+---------------------------------------------------------------------+</pre>
<p>こうなる。</p>
<p></p>
<p></p>AWS RDS MySQLのレプリケーションが止まったので復旧2017-01-03T12:34:40+00:002024-03-27T18:57:30+00:00ytynghttps://b.ytyng.com/blog/author/ytyng/https://b.ytyng.com/blog/aws-rds-mysql-replication-failed/<div>AWS RDS MySQL のレプリケーションの様子がおかしい</div>
<div></div>
<div>MyIsam テーブルがありますが、</div>
<div>CHECK TABLE xxxx_xxxx;</div>
<div></div>
<div>してみると</div>
<div></div>
<div>Table Op Msg_type Msg_text</div>
<div>xxxx.<span>xxxx_xxxx</span> check error Corrupt</div>
<div></div>
<div><img alt="" height="77" src="https://www.ytyng.com/media/uploads/blog/aws/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88_2016-09-13_18.34.00.png" width="418"/></div>
<div></div>
<div>Msg_text が Corrupt。このテーブルは腐ってると言われます。マスターの方は問題無し。</div>
<div></div>
<div>AWS コンソールの RDS ページを見てみると</div>
<div></div>
<div><img alt="" height="222" src="https://www.ytyng.com/media/uploads/blog/aws/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88_2016-09-13_18.28.06.png" width="458"/></div>
<div></div>
<div></div>
<div>レプリケーションが失敗している</div>
<div></div>
<div>SHOW SLAVE STATUS を見ると</div>
<div></div>
<pre>{<br/> "data":<br/> [<br/> {<br/> "Slave_IO_State": "Waiting for master to send event",<br/> "Master_Host": "10.7.1.169",<br/> "Master_User": "rdsrepladmin",<br/> "Master_Port": 3306,<br/> "Connect_Retry": 60,<br/> "Master_Log_File": "mysql-bin-changelog.131739",<br/> "Read_Master_Log_Pos": 743597,<br/> "Relay_Log_File": "relaylog.000242",<br/> "Relay_Log_Pos": 496325,<br/> "Relay_Master_Log_File": "mysql-bin-changelog.131676",<br/> "Slave_IO_Running": "Yes",<br/> "Slave_SQL_Running": "No",<br/> "Replicate_Do_DB": "",<br/> "Replicate_Ignore_DB": "",<br/> "Replicate_Do_Table": "",<br/> "Replicate_Ignore_Table": "mysql.plugin,mysql.rds_monitor,mysql.rds_sysinfo,mysql.rds_replication_status,mysql.rds_history,innodb_memcache.config_options,innodb_memcache.cache_policies",<br/> "Replicate_Wild_Do_Table": "",<br/> "Replicate_Wild_Ignore_Table": "",<br/> "Last_Errno": 1053,<br/> "Last_Error": "Query partially completed on the master (error on master: 1053) and was aborted. There is a chance that your master is inconsistent at this point. If you are sure that your master is ok, run this query manually on the slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; . Query: 'UPDATE xxxxx SET xxxxxxxxxxxxxxxxxxx'",<br/> "Skip_Counter": 0,<br/> "Exec_Master_Log_Pos": 496152,<br/> "Relay_Log_Space": 428001772,<br/> "Until_Condition": "None",<br/> "Until_Log_File": "",<br/> "Until_Log_Pos": 0,<br/> "Master_SSL_Allowed": "No",<br/> "Master_SSL_CA_File": "",<br/> "Master_SSL_CA_Path": "",<br/> "Master_SSL_Cert": "",<br/> "Master_SSL_Cipher": "",<br/> "Master_SSL_Key": "",<br/> "Seconds_Behind_Master": null,<br/> "Master_SSL_Verify_Server_Cert": "No",<br/> "Last_IO_Errno": 0,<br/> "Last_IO_Error": "",<br/> "Last_SQL_Errno": 1053,<br/> "Last_SQL_Error": "Query partially completed on the master (error on master: 1053) and was aborted. There is a chance that your master is inconsistent at this point. If you are sure that your master is ok, run this query manually on the slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; . Query: 'UPDATE xxxxx SET xxxxxxxxxxxxxxxxxxx'",<br/> "Replicate_Ignore_Server_Ids": "",<br/> "Master_Server_Id": 1498488124,<br/> "Master_UUID": "e247ce2a-13ee-11e5-8f81-0adacdd7d587",<br/> "Master_Info_File": "mysql.slave_master_info",<br/> "SQL_Delay": 0,<br/> "SQL_Remaining_Delay": null,<br/> "Slave_SQL_Running_State": "",<br/> "Master_Retry_Count": 86400,<br/> "Master_Bind": "",<br/> "Last_IO_Error_Timestamp": "",<br/> "Last_SQL_Error_Timestamp": "160913 09:37:11",<br/> "Master_SSL_Crl": "",<br/> "Master_SSL_Crlpath": "",<br/> "Retrieved_Gtid_Set": "",<br/> "Executed_Gtid_Set": "",<br/> "Auto_Position": 0<br/> }<br/> ]<br/>}</pre>
<div></div>
<div></div>
<div>強制停止したクエリで引っかかっている</div>
<div></div>
<div></div>
<pre> "Slave_IO_Running": "Yes",<br/> "Slave_SQL_Running": "No",</pre>
<div></div>
<pre>SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;</pre>
<div></div>
<div>→ Access Denied!</div>
<div></div>
<div>復旧できない</div>
<div></div>
<div></div>
<div><a href="http://f-retu.hatenablog.com/entry/2013/11/21/080720" target="_blank">【AWS,RDS,MySQL】RDS(MySQL)のリードレプリカでレプリケーションエラーが出た際の対処 - へろへろもへじ</a></div>
<div></div>
<div>こちらを参考に</div>
<div></div>
<pre>CALL mysql.rds_skip_repl_error;</pre>
<div></div>
<div></div>
<pre>"Slave_IO_Running": "Yes",<br/>"Slave_SQL_Running": "Yes",</pre>
<div>なおった</div>MySQL の 照合順序 utf8_unicode_ci はけっこう遅いのでやめとくべき2016-09-14T09:44:56+00:002024-03-27T07:16:18+00:00ytynghttps://b.ytyng.com/blog/author/ytyng/https://b.ytyng.com/blog/mysql-collate-utf8_unicode_ci-utf8_general_ci/<p>まったく定量的な話でないのですが。</p>
<p>某サービスで、MyISAM のテーブルのフィールドにフルテキストインデックスをつけて、バイグラムで検索インデックスを入れてました。20万レコードぐらい。</p>
<p>今までは、そのフィールドの文字コードの照合順序 ( collate ) は utf8_general_ci (デフォルト) だったんですが、日本語でカタカナ平仮名両方マッチさせたいので、collate を utf8_unicode_ci に変えてみたんです。</p>
<p>そうしたら、パフォーマンスが極端に悪くなり全然サービスが動かなくなってしまって。SHOW FULL PROCESSLIST; 見たら検索クエリが詰まってる。</p>
<p>ということで、utf8_unicode_ci やめて元に戻しました。日本語のカタカナ平仮名のゆれは、検索データを入れる際にノーマライズして入れることにしました。</p>
<p>utf8_unicode_ci やめといたほうがいい、という話。というか検索系は MySQL + フルテキストインデックスでやるより、Elasticsearch とか Cloudsearch とか使ったほうが良いですね。</p>
<p></p>MySQL InnoDBのフルテキストインデックスで、ストップワードフィルタを無効にする (in, by, is などで検索できるようにする)2015-12-01T06:42:57+00:002024-03-25T03:54:50+00:00ytynghttps://b.ytyng.com/blog/author/ytyng/https://b.ytyng.com/blog/MySQLInnoDB%E3%81%AE%E3%83%95%E3%83%AB%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%A7%E3%80%81%E3%82%B9%E3%83%88%E3%83%83%E3%83%97%E3%83%AF%E3%83%BC%E3%83%89%E3%83%95%E3%82%A3%E3%83%AB%E3%82%BF%E3%82%92%E7%84%A1%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B(in,by,is%E3%81%AA%E3%81%A9%E3%81%A7%E6%A4%9C%E7%B4%A2%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%99%E3%82%8B)/<div class="document">
<div class="section" id="id1">
<h3>経緯</h3>
<p>MySQL5.6 の、InnoDB にバイグラムでフルテキストインデックスを作っているのですが、
TWIN という文字を検索しようとした所、</p>
<pre class="literal-block">SELECT COUNT(*) FROM ...
WHERE MATCH(search_text) AGAINST ('+tw +wi +in' IN BOOLEAN MODE)
</pre>
<p>... 結果が出てきません。</p>
<p>'+tw +wi' だと結果があります(twin がヒットします)。</p>
<p>調査した所、「ストップワード」という機能があり、in や by, is なんかは検索インデックスが作られないようになっている仕様でした。</p>
<p>※ InnoDB のフルテキストインデックスの場合のみ。MyISAM の場合は、デフォルトはストップワードテーブルは使われない。</p>
<p>ストップワードの内容を表示するには</p>
<pre class="literal-block">SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_DEFAULT_STOPWORD;
</pre>
<p>in, is, it, la, of, on などが入ってます。</p>
<p>このテーブルは、自分で別のテーブルを作ってそちらを使うように設定もできますが、今回はそもそもストップワードテーブルを使ってのインデックス生成フィルタリングを無効にします。</p>
<p>無効にせず、ストップワードテーブルを差し替えるにはこちらのページが参考になります。</p>
<p>MySQL :: MySQL 5.6 リファレンスマニュアル :: 12.9.4 全文ストップワード</p>
<p><a class="reference external" href="https://dev.mysql.com/doc/refman/5.6/ja/fulltext-stopwords.html">https://dev.mysql.com/doc/refman/5.6/ja/fulltext-stopwords.html</a></p>
</div>
<div class="section" id="id2">
<h3>ストップワードを無効にする設定</h3>
<p>InnoDB でのストップワード判定を無効にするには、設定の innodb_ft_enable_stopword を変更します。</p>
<p>現状の確認</p>
<pre class="literal-block">SHOW VARIABLES LIKE 'innodb_ft_enable_stopword';
</pre>
<pre class="literal-block">innodb_ft_enable_stopword ON
</pre>
<p>デフォルトでは有効になっています。</p>
<p>なので、my.cnf などの設定ファイルに</p>
<pre class="literal-block">[mysqld]
innodb_ft_enable_stopword = OFF
</pre>
<p>として、MySQL を再起動すると</p>
<pre class="literal-block">SHOW VARIABLES LIKE 'innodb_ft_enable_stopword';
</pre>
<pre class="literal-block">innodb_ft_enable_stopword OFF
</pre>
<p>反映されます。</p>
<p>Ubuntu なんかでは、 /etc/mysql/conf.d/ ディレクトリが用意されているので、その中に設定ファイルを放り込むと良いでしょう。</p>
<p>僕のはこんな感じ</p>
<p>/etc/mysql/conf.d/fulltext_search.cnf</p>
<pre class="literal-block">[mysqld]
# Fulltext search bigram settings.
ft_min_word_len = 2
innodb_ft_min_token_size = 2
innodb_ft_enable_stopword = OFF
</pre>
</div>
<div class="section" id="id3">
<h3>検索インデックスの再生成</h3>
<p>インデックスの再生成は、</p>
<p>REPAIR TABLE table_name QUICK; ではなく (これは MyISAM の場合)</p>
<p>InnoDB の場合は</p>
<pre class="literal-block">ALTER TABLE table_name FORCE;
</pre>
<p>で行えます。</p>
<pre class="literal-block">SELECT COUNT(*) FROM ...
WHERE MATCH(search_text) AGAINST ('+tw +wi +in' IN BOOLEAN MODE)
</pre>
<p>→ 結果でました!</p>
</div>
</div>