MySQL Boolean類型的坑


MySQL中,Boolean只是 tinyint(1) 的別名,也就是說,MySQL中並沒有真正的bool類型。

而SQLAlchemy生成SQL的時候並沒有檢測到 這一點,這就導致一個問題,當使用 bool 類型作為查詢條件時,用不上索引,從而導致掃表的行為:

> SELECT COUNT(*) FROM message WHERE message.is_national = 1
 AND message.updated_at > '2020-01-01 00:00:00' AND message.deleted_at IS NULL;
+----------+
| COUNT(*) |
+----------+
| 0        |
+----------+
1 row in set
Time: 0.018s
> SELECT COUNT(*) FROM message WHERE message.is_national is true 
AND message.updated_at > '2020-01-01 00:00:00' AND message.deleted_at IS NULL;
+----------+
| COUNT(*) |
+----------+
| 0        |
+----------+
1 row in set
Time: 2.162s
sql

注意觀察第一行和第二行的時間,很明顯第二行沒有用上索引,我們來看看 EXPLAIN 的結果便知道了:

> EXPLAIN SELECT COUNT(*) FROM message WHERE message.is_national = 1 AND message.updated_at > '2020-01-01 00:00:00' AND message.de
        leted_at IS NULL;
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
| 1  | SIMPLE | message | ref  | ix_message_updated_at,idx_updated_at_is_national,ix_message_is_national | ix_message_is_national | 1 | const | 1 | Using where |

> EXPLAIN SELECT COUNT(*) FROM message WHERE message.is_national is true AND message.updated_at > '2020-01-01 00:00:00' AND messag
e.deleted_at IS NULL;
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
| 1 | SIMPLE | message | ALL | ix_message_updated_at,idx_updated_at_is_national | <null> | <null> | <null> | 一個很大的數字 | Using whe
re
|

explain

 

 

mysql文檔給出的解釋

java.lang.Boolean if the configuration property tinyInt1isBit is set to true (the default) and the storage size is 1, or java.lang.Integer if not.

要注意下面這個提示

The ResultSet.getObject() method uses the type conversions between MySQL and Java types, following the JDBC specification where appropriate. The values returned by ResultSetMetaData.GetColumnTypeName()and ResultSetMetaData.GetColumnClassName() are shown in the table below. For more information on the JDBC types, see the reference on the java.sql.Types class.

文檔地址:https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-type-conversions.html

 

解決方案:

1.使用ifnull(column, 0)處理該字段,個人測試過可以;
2.在JDBC的URL增加 tinyInt1isBit=false參數,注意參數名區分大小寫,否則不生效(默認為true)
即:jdbc:mysql://${ucmha.proxy1_2.host}/${db.mysql.db}?tinyInt1isBit=false
3.避免使用長度為1的tinyint類型字段存儲數字格式的數據;


參考資料:


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM