热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

MySQL之leftjoin表查询中发生字符集转换导致表索引失效

mysql,之,left,join,表,查询,中,发生,字符,集,转换,

一、出现的场景

研发leader突然给了1条sql说这条sql在测试环境库db-stage执行非常的慢,放到线上db-read从库上执行非常的快。而且线上库从库的表的数据远多于测试环境库的表数据。让我分析下是什么问题??

二、sql内容如下

 select odtl.id from db_order.t_order_device_trans_log odtl left join db_order.t_order_items_detail oid on odtl.order_id=oid.order_id left join db_order.t_orders o on oid.order_id=o.order_id where oid.customer_id= 40933 group by o.order_id;

对此sql简单分析如下:
此sql包含了3个表的 left join 查询
db_order.t_order_device_trans_log db_order.t_order_items_detail 和db_order.t_orders 表连接组成,分别用了odtl、 oid、 o 别名表示。因为都是用的 LEFT JOIN,所以表连接顺序应该是 odtl-->oid-->o,和explain 执行计划中显示的一致。

三、验证explain计划

本以为测试环境库配置参数和线上db-read库配置参数都是一样的。研发的话不能全信。还是拿着sql在测试库db-stage和线上db-read1 (Mariadb库版本10.2.17),db-read4(mysql5.7.32) 跑了下

3.1、db-stage环境上的sql的执行计划:

mysql>explain select odtl.id from db_order.t_order_device_trans_log odtl left join db_order.t_order_items_detail oid on odtl.order_id=oid.order_id left join db_order.t_orders o on oid.order_id=o.order_id where oid.customer_id= 40933 group by o.order_id; +----+-------------+-------+------------+--------+------------------------------------------------------------------------------------+-----------+---------+-----------------------+--------+----------+----------------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+--------+------------------------------------------------------------------------------------+-----------+---------+-----------------------+--------+----------+----------------------------------------------+ | 1 | SIMPLE | odtl | NULL | index | NULL | idx_order | 62 | NULL | 785867 | 100.00 | Using index; Using temporary; Using filesort | | 1 | SIMPLE | oid | NULL | ref | order_id,customer_id | order_id | 82 | func | 3 | 1.39 | Using index condition; Using where | | 1 | SIMPLE | o | NULL | eq_ref | PRIMARY,order_id,main_order_id,customer_id_bill,source_order_id,idx_is_sale_status | order_id | 82 | db_order.oid.order_id | 1 | 100.00 | Using index | +----+-------------+-------+------------+--------+------------------------------------------------------------------------------------+-----------+---------+-----------------------+--------+----------+----------------------------------------------+ 3 rows in set, 1 warning (0.00 sec)

分析:
发现别名表 odtl type 类型为index,说明一开始是选择了索引的 possible_keys为NULL key:存在索引idx_order,但是没走索引,并且进行了全表扫描。

3.2、线上从库db-read4环境上的sql的执行计划:

'db-read4>explain select odtl.id from db_order.t_order_device_trans_log odtl left join db_order.t_order_items_detail oid on odtl.order_id=oid.order_id left join db_order.t_orders o on oid.order_id=o.order_id where oid.customer_id= 40933 group by o.order_id; +----+-------------+-------+------------+--------+-----------------------------------------------------------------+-------------+---------+-----------------------+------+----------+----------------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+--------+-----------------------------------------------------------------+-------------+---------+-----------------------+------+----------+----------------------------------------------+ | 1 | SIMPLE | oid | NULL | ref | order_id,customer_id | customer_id | 4 | const | 279 | 100.00 | Using where; Using temporary; Using filesort | | 1 | SIMPLE | o | NULL | eq_ref | PRIMARY,order_id,main_order_id,customer_id_bill,source_order_id | order_id | 82 | db_order.oid.order_id | 1 | 100.00 | Using index | | 1 | SIMPLE | odtl | NULL | ref | idx_order | idx_order | 82 | db_order.oid.order_id | 7 | 100.00 | Using index | +----+-------------+-------+------------+--------+-----------------------------------------------------------------+-------------+---------+-----------------------+------+----------+----------------------------------------------+ 3 rows in set, 1 warning (0.00 sec)

分析:
发现别名表 odtl type类型为ref ,说明选择了ref级别索引; possible_keys为 idx_order; key:存在索引idx_order ,而且走了索引的。

3.3、线上从库db-read1环境上的sql的执行计划:

root@db-read1 13:17: [(none)]> explain select odtl.id from db_order.t_order_device_trans_log odtl left join db_order.t_order_items_detail oid on odtl.order_id=oid.order_id left join db_order.t_orders o on oid.order_id=o.order_id where oid.customer_id= 40933 group by o.order_id; +------+-------------+-------+--------+----------------------+-------------+---------+-----------------------+------+---------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+-------+--------+----------------------+-------------+---------+-----------------------+------+---------------------------------+ | 1 | SIMPLE | oid | ref | order_id,customer_id | customer_id | 4 | const | 279 | Using temporary; Using filesort | | 1 | SIMPLE | o | eq_ref | order_id | order_id | 82 | db_order.oid.order_id | 1 | Using index | | 1 | SIMPLE | odtl | ref | idx_order | idx_order | 82 | db_order.oid.order_id | 3 | Using index | +------+-------------+-------+--------+----------------------+-------------+---------+-----------------------+------+---------------------------------+ 3 rows in set (0.01 sec)

分析:
发现别名表 odtl type类型为ref ,说明选择了ref级别索引; possible_keys为 idx_order; key:存在索引idx_order ,而且走了索引的。

结果:db-stage库确实是全表扫描了。确实比较奇怪。到底是什么问题导致的呢?
检查了下这条sql涉及到的这3个表的索引结构(测试环境和线上环境)。没发现有任何不同。太奇怪了。

3.4、采用explain format=json 方式查看执行计划

换了一种方式查看sql的执行计划:找到了线索

指定explain执行计划的线上格式为JSON。可以更详细的显示出执行计划的具体信息(建议生产上多多使用此方法分析sql执行计划)

在db-stage库上执行分析:

 mysql> explain format=json select odtl.id from db_order.t_order_device_trans_log odtl left join db_order.t_order_items_detail oid on odtl.order_id=oid.order_id left join db_order.t_orderss o on oid.order_id=o.order_id where oid.customer_id= 40933 group by o.order_id\G *************************** 1. row *************************** EXPLAIN: { "query_block": { "select_id": 1, "cost_info": { "query_cost": "3634954.72" }, "grouping_operation": { "using_temporary_table": true, "using_filesort": true, "cost_info": { "sort_cost": "39293.35" }, "nested_loop": [ { "table": { "table_name": "odtl", "access_type": "index", "key": "idx_order", "used_key_parts": [ "order_id" ], "key_length": "62", "rows_examined_per_scan": 785867, "rows_produced_per_join": 785867, "filtered": "100.00", "using_index": true, "cost_info": { "read_cost": "4007.00", "eval_cost": "157173.40", "prefix_cost": "161180.40", "data_read_per_join": "179M" }, "used_columns": [ "id", "order_id" ] } }, { "table": { "table_name": "oid", "access_type": "ref", "possible_keys": [ "order_id", "customer_id" ], "key": "order_id", "used_key_parts": [ "order_id" ], "key_length": "82", "ref": [ "func" ], "rows_examined_per_scan": 3, "rows_produced_per_join": 39293, "filtered": "1.39", "index_condition": "(convert(`db_order`.`odtl`.`order_id` using utf8mb4) = `db_order`.`oid`.`order_id`)", "cost_info": { "read_cost": "2822774.13", "eval_cost": "7858.67", "prefix_cost": "3548509.35", "data_read_per_join": "218M" }, "used_columns": [ "id", "order_id", "customer_id" ], "attached_condition": "(`db_order`.`oid`.`customer_id` = 40933)" } }, { "table": { "table_name": "o", "access_type": "eq_ref", "possible_keys": [ "PRIMARY", "order_id", "main_order_id", "customer_id_bill", "source_order_id", "idx_is_sale_status" ], "key": "order_id", "used_key_parts": [ "order_id" ], "key_length": "82", "ref": [ "db_order.oid.order_id" ], "rows_examined_per_scan": 1, "rows_produced_per_join": 39293, "filtered": "100.00", "using_index": true, "cost_info": { "read_cost": "39293.35", "eval_cost": "7858.67", "prefix_cost": "3595661.37", "data_read_per_join": "474M" }, "used_columns": [ "id", "order_id" ] } } ] } } } 1 row in set, 1 warning (0.00 sec)

执行计划分析:

计划index_condition条件中显示如下:发现了别名表odtl字段order_id =匹配别名表oid字段order_id时出现了utf8mb4字符集的转换

 "index_condition": "(convert(`db_order`.`odtl`.`order_id` using utf8mb4) = `db_order`.`oid`.`order_id`)",

豁然开朗,很有可能是表db_order.t_order_device_trans_log 字段order_id字符集和db_order.t_order_items_detail表字段order_id字符集不一样,导致执行sql过程中,使得原本的索引失效,造成db_order.t_order_device_trans_log全表的扫描

于是在db-read1和db-read4库也同样执行json格式的explain计划:指标都是正常走索引的

 'db-read4' root@localhost 23:08:05 (none)>explain format=json select odtl.id from db_order.t_order_device_trans_log odtl left join db_order.t_order_items_detail oid on odtl.order_id=oid.order_id left join db_order.t_orders o on oid.order_id=o.order_id where oid.customer_id= 40933 group by o.order_id\G *************************** 1. row *************************** EXPLAIN: { "query_block": { "select_id": 1, "cost_info": { "query_cost": "3395.51" }, "grouping_operation": { "using_temporary_table": true, "using_filesort": true, "cost_info": { "sort_cost": "2023.29" }, "nested_loop": [ { "table": { "table_name": "oid", "access_type": "ref", "possible_keys": [ "order_id", "customer_id" ], "key": "customer_id", "used_key_parts": [ "customer_id" ], "key_length": "4", "ref": [ "const" ], "rows_examined_per_scan": 279, "rows_produced_per_join": 279, "filtered": "100.00", "cost_info": { "read_cost": "279.00", "eval_cost": "55.80", "prefix_cost": "334.80", "data_read_per_join": "1M" }, "used_columns": [ "id", "order_id", "customer_id" ], "attached_condition": "(`db_order`.`oid`.`order_id` is not null)" } }, { "table": { "table_name": "o", "access_type": "eq_ref", "possible_keys": [ "PRIMARY", "order_id", "main_order_id", "customer_id_bill", "source_order_id" ], "key": "order_id", "used_key_parts": [ "order_id" ], "key_length": "82", "ref": [ "db_order.oid.order_id" ], "rows_examined_per_scan": 1, "rows_produced_per_join": 279, "filtered": "100.00", "using_index": true, "cost_info": { "read_cost": "279.00", "eval_cost": "55.80", "prefix_cost": "669.60", "data_read_per_join": "3M" }, "used_columns": [ "id", "order_id" ] } }, { "table": { "table_name": "odtl", "access_type": "ref", "possible_keys": [ "idx_order" ], "key": "idx_order", "used_key_parts": [ "order_id" ], "key_length": "82", "ref": [ "db_order.oid.order_id" ], "rows_examined_per_scan": 7, "rows_produced_per_join": 2023, "filtered": "100.00", "using_index": true, "cost_info": { "read_cost": "297.96", "eval_cost": "404.66", "prefix_cost": "1372.22", "data_read_per_join": "616K" }, "used_columns": [ "id", "order_id" ] } } ] } } } 1 row in set, 1 warning (0.00 sec)
 root@db-read1 13:38: [(none)]> explain format=json select odtl.id from db_order.t_order_device_trans_log odtl left join db_order.t_order_items_detail oid on odtl.order_id=oid.order_id left join db_order.t_orders o on oid.order_id=o.order_id where oid.customer_id= 40933 group by o.order_id\G *************************** 1. row *************************** EXPLAIN: { "query_block": { "select_id": 1, "filesort": { "sort_key": "db_order.o.order_id", "temporary_table": { "table": { "table_name": "oid", "access_type": "ref", "possible_keys": ["order_id", "customer_id"], "key": "customer_id", "key_length": "4", "used_key_parts": ["customer_id"], "ref": ["const"], "rows": 279, "filtered": 100 }, "table": { "table_name": "o", "access_type": "eq_ref", "possible_keys": ["order_id"], "key": "order_id", "key_length": "82", "used_key_parts": ["order_id"], "ref": ["db_order.oid.order_id"], "rows": 1, "filtered": 100, "using_index": true }, "table": { "table_name": "odtl", "access_type": "ref", "possible_keys": ["idx_order"], "key": "idx_order", "key_length": "82", "used_key_parts": ["order_id"], "ref": ["db_order.oid.order_id"], "rows": 3, "filtered": 100, "using_index": true } } } } } 1 row in set (0.00 sec)

四、查看表字符集确定最终的问题

问题就是db-stage 库 表db_order.t_order_device_trans_log 字符集居然是utf8导致的索引失效。

于是查看测试库db-stage 表db_order.t_order_device_trans_log 字符集居然是utf8 mysql> show create table db_order.t_order_device_trans_log\G *************************** 1. row *************************** Table: t_order_device_trans_log Create Table: CREATE TABLE `t_order_device_trans_log` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `order_id` varchar(20) NOT NULL COMMENT '订单号', `order_type` tinyint(2) NOT NULL COMMENT '订单类型', `rent_type` tinyint(2) NOT NULL COMMENT '租赁类型(1.随租随还2.固定租期3.租完即送4.无期限随租随还5.短期租赁)', `item_detail_id` bigint(20) NOT NULL COMMENT '订单设备id', `sn` varchar(50) NOT NULL COMMENT '序列号', `before_status` tinyint(2) DEFAULT NULL COMMENT '变更前设备状态', `change_type` tinyint(2) NOT NULL COMMENT '变更类型:0:已发货,1:起租,2:退租,3:融租完成,4:挂应收,5:换货, 99:取消发货', `cdate` datetime NOT NULL, PRIMARY KEY (`id`), KEY `idx_order` (`order_id`) ) ENGINE=InnoDB AUTO_INCREMENT=3794673 DEFAULT CHARSET=utf8 1 row in set (0.00 sec)

db-stage库其他2个表db_order.t_order_items_detail 和db_order.t_orders 字符集都是 utf8mb4

于是查看测试库db-read1 表db_order.t_order_device_trans_log db_order.t_order_items_detail 和db_order.t_orders 字符集utf8mb4
于是查看测试库db-read4 表db_order.t_order_device_trans_log db_order.t_order_items_detail 和db_order.t_orders 字符集utf8mb4

五、修改表字符集utf8为utf8mb4

切记:修改表字符集前一定要对表提前做下备份

mysqldump -uroot -p'UEgzFO' -h 127.0.0.1 db_order t_order_device_trans_log > /data/dump/2021-04-13.t_order_device_trans_log.sql 

5.1 修改表字符集前的建表sql:

 mysql> show create table db_order.t_order_device_trans_log\G *************************** 1. row *************************** Table: t_order_device_trans_log Create Table: CREATE TABLE `t_order_device_trans_log` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `order_id` varchar(20) NOT NULL COMMENT '订单号', `order_type` tinyint(2) NOT NULL COMMENT '订单类型', `rent_type` tinyint(2) NOT NULL COMMENT '租赁类型(1.随租随还2.固定租期3.租完即送4.无期限随租随还5.短期租赁)', `item_detail_id` bigint(20) NOT NULL COMMENT '订单设备id', `sn` varchar(50) NOT NULL COMMENT '序列号', `before_status` tinyint(2) DEFAULT NULL COMMENT '变更前设备状态', `change_type` tinyint(2) NOT NULL COMMENT '变更类型:0:已发货,1:起租,2:退租,3:融租完成,4:挂应收,5:换货, 99:取消发货', `cdate` datetime NOT NULL, PRIMARY KEY (`id`), KEY `idx_order` (`order_id`) ) ENGINE=InnoDB AUTO_INCREMENT=3794673 DEFAULT CHARSET=utf8 1 row in set (0.00 sec)

占用磁盘的大小:

mysql> select count(*) from db_order.t_order_device_trans_log\G *************************** 1. row *************************** count(*): 962234 1 row in set (0.19 sec) mysql> SELECT (`DATA_LENGTH`+ `INDEX_LENGTH`)/1024/1024 as `table_data_size` from `TABLES` WHERE TABLE_NAME ='t_order_device_trans_log' and TABLE_SCHEMA='db_order'; +-----------------+ | table_data_size | +-----------------+ | 62.60937500 | +-----------------+ 1 row in set (0.00 sec)

5.2修改db-stage测试库表字符集为utf8mb4:

下面的操作是错误的,才导致后面执行sql报错

 mysql > ALTER TABLE db_order.t_order_device_trans_log CONVERT TO CHARACTER SET utf8mb4; Query OK, 962234 rows affected (17.99 sec) Records: 962234 Duplicates: 0 Warnings: 0 mysql> show create table db_order.t_order_device_trans_log\G *************************** 1. row *************************** Table: t_order_device_trans_log Create Table: CREATE TABLE `t_order_device_trans_log` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `order_id` varchar(20) NOT NULL COMMENT '订单号', `order_type` tinyint(2) NOT NULL COMMENT '订单类型', `rent_type` tinyint(2) NOT NULL COMMENT '租赁类型(1.随租随还2.固定租期3.租完即送4.无期限随租随还5.短期租赁)', `item_detail_id` bigint(20) NOT NULL COMMENT '订单设备id', `sn` varchar(50) NOT NULL COMMENT '序列号', `before_status` tinyint(2) DEFAULT NULL COMMENT '变更前设备状态', `change_type` tinyint(2) NOT NULL COMMENT '变更类型:0:已发货,1:起租,2:退租,3:融租完成,4:挂应收,5:换货, 99:取消发货', `cdate` datetime NOT NULL, PRIMARY KEY (`id`), KEY `idx_order` (`order_id`) ) ENGINE=InnoDB AUTO_INCREMENT=3794673 DEFAULT CHARSET=utf8mb4 1 row in set (0.00 sec) 执行计划报错: mysql> explain select odtl.id from db_order.t_order_device_trans_log odtl left join db_order.t_order_items_detail oid on odtl.order_id=oid.order_id left join db_order.t_orders o on oid.order_id=o.order_id where oid.customer_id= 40933 group by o.order_id; ERROR 1267 (HY000): Illegal mix of collations (utf8mb4_general_ci,IMPLICIT) and (utf8mb4_unicode_ci,IMPLICIT) for operation '='
mysql> ALTER TABLE t_order_device_trans_log DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 0

查看执行计划,还在报错:

 mysql> explain select odtl.id from db_order.t_order_device_trans_log odtl left join db_order.t_order_items_detail oid on odtl.order_id=oid.order_id left join db_order.t_orders o on oid.order_id=o.order_id where oid.customer_id= 40933 group by o.order_id; ERROR 1267 (HY000): Illegal mix of collations (utf8mb4_general_ci,IMPLICIT) and (utf8mb4_unicode_ci,IMPLICIT) for operation '=' 

5.3解决办法就是还原成原来的表字符集utf8。然后重新修改表字符集为utf8mb4:

重要提示:下面的参数可以不重启MySQL服务进行动态设置。同时也要主要my.cnf配置文件字符集参数的设置

 [root@db-stage ~]# egrep "character|collation_server" /etc/my.cnf default-character-set=utf8mb4 #character-set-server=utf8 character_set_server = 'utf8mb4' collation_server = 'utf8mb4_unicode_ci' #collation_server = 'utf8mb4_general_ci'

5.4下面的操作是还原一开始表db_order.t_order_device_trans_log的字符集utf8

下面是还原原来表字符集 utf8:

mysql> ALTER TABLE db_order.t_order_device_trans_log CONVERT TO CHARACTER SET utf8; Query OK, 962234 rows affected (17.99 sec) Records: 962234 Duplicates: 0 Warnings: 0

再次执行下面的修改表字符集utf8mb4为命令:

mysql> ALTER TABLE db_order.t_order_device_trans_log CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; Query OK, 962784 rows affected (18.99 sec) Records: 962784 Duplicates: 0 Warnings: 0
 mysql> show create table db_order.t_order_device_trans_log\G *************************** 1. row *************************** Table: t_order_device_trans_log Create Table: CREATE TABLE `t_order_device_trans_log` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `order_id` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '订单号', `order_type` tinyint(2) NOT NULL COMMENT '订单类型', `rent_type` tinyint(2) NOT NULL COMMENT '租赁类型(1.随租随还2.固定租期3.租完即送4.无期限随租随还5.短期租赁)', `item_detail_id` bigint(20) NOT NULL COMMENT '订单设备id', `sn` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '序列号', `before_status` tinyint(2) DEFAULT NULL COMMENT '变更前设备状态', `change_type` tinyint(2) NOT NULL COMMENT '变更类型:0:已发货,1:起租,2:退租,3:融租完成,4:挂应收,5:换货, 99:取消发货', `cdate` datetime NOT NULL, PRIMARY KEY (`id`), KEY `idx_order` (`order_id`) ) ENGINE=InnoDB AUTO_INCREMENT=3795223 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci 1 row in set (0.00 sec) mysql> show variables where Variable_name like 'collation%'; +----------------------+--------------------+ | Variable_name | Value | +----------------------+--------------------+ | collation_connection | utf8mb4_general_ci | | collation_database | utf8mb4_unicode_ci | | collation_server | utf8mb4_unicode_ci | +----------------------+--------------------+ 3 rows in set (0.01 sec)

查看表占用磁盘物理空间大小:

mysql> use information_schema; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> SELECT (`DATA_LENGTH`+ `INDEX_LENGTH`)/1024/1024 as `table_data_size` from `TABLES` WHERE TABLE_NAME ='t_order_device_trans_log' and TABLE_SCHEMA='db_order'; +-----------------+ | table_data_size | +-----------------+ | 142.35937500 | +-----------------+ 1 row in set (0.00 sec)

此时查看db-stage json格式的执行计划:

 mysql> explain format=json select odtl.id from db_order.t_order_device_trans_log odtl left join db_order.t_order_items_detail oid on odtl.order_id=oid.order_id left join db_order.t_ordeers o on oid.order_id=o.order_id where oid.customer_id= 40933 group by o.order_id\G *************************** 1. row *************************** EXPLAIN: { "query_block": { "select_id": 1, "cost_info": { "query_cost": "1073.53" }, "grouping_operation": { "using_temporary_table": true, "using_filesort": true, "cost_info": { "sort_cost": "589.89" }, "nested_loop": [ { "table": { "table_name": "oid", "access_type": "ref", "possible_keys": [ "order_id", "customer_id" ], "key": "customer_id", "used_key_parts": [ "customer_id" ], "key_length": "4", "ref": [ "const" ], "rows_examined_per_scan": 106, "rows_produced_per_join": 106, "filtered": "100.00", "cost_info": { "read_cost": "106.00", "eval_cost": "21.20", "prefix_cost": "127.20", "data_read_per_join": "602K" }, "used_columns": [ "id", "order_id", "customer_id" ], "attached_condition": "(`db_order`.`oid`.`order_id` is not null)" } }, { "table": { "table_name": "o", "access_type": "eq_ref", "possible_keys": [ "PRIMARY", "order_id", "main_order_id", "customer_id_bill", "source_order_id", "idx_is_sale_status" ], "key": "order_id", "used_key_parts": [ "order_id" ], "key_length": "82", "ref": [ "db_order.oid.order_id" ], "rows_examined_per_scan": 1, "rows_produced_per_join": 106, "filtered": "100.00", "using_index": true, "cost_info": { "read_cost": "106.00", "eval_cost": "21.20", "prefix_cost": "254.40", "data_read_per_join": "1M" }, "used_columns": [ "id", "order_id" ] } }, { "table": { "table_name": "odtl", "access_type": "ref", "possible_keys": [ "idx_order" ], "key": "idx_order", "used_key_parts": [ "order_id" ], "key_length": "82", "ref": [ "db_order.oid.order_id" ], "rows_examined_per_scan": 5, "rows_produced_per_join": 589, "filtered": "100.00", "using_index": true, "cost_info": { "read_cost": "111.26", "eval_cost": "117.98", "prefix_cost": "483.64", "data_read_per_join": "179K" }, "used_columns": [ "id", "order_id" ] } } ] } } } 1 row in set, 1 warning (0.00 sec) mysql> 

MySQL之left join表查询中发生字符集转换导致表索引失效

到此处完成sql的优化

六、过程总结:

通过这次问题排查,发现了字符集不同是也会导致索引失效。这个问题有点类似于 int=varchar 隐式转换问题,等号左边为 int 类型,右边为 varchar 类型,那么 MySQL 会自动转换类型为一致,因而无法走索引。
另外还有一个注意的点就是,列的字符集也有可能与表的字符集不同!这种情况也是会导致索引失效问题的。 所以一定要严格要求MySQL建表规范,要求表必须有主键,且表的字符集和字段的字符集必须一致。这样才能避免踩坑。字符集不一致,字符集转换导致索引失效的问题


推荐阅读
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
  • VueCLI多页分目录打包的步骤记录
    本文介绍了使用VueCLI进行多页分目录打包的步骤,包括页面目录结构、安装依赖、获取Vue CLI需要的多页对象等内容。同时还提供了自定义不同模块页面标题的方法。 ... [详细]
  • MySQL多表数据库操作方法及子查询详解
    本文详细介绍了MySQL数据库的多表操作方法,包括增删改和单表查询,同时还解释了子查询的概念和用法。文章通过示例和步骤说明了如何进行数据的插入、删除和更新操作,以及如何执行单表查询和使用聚合函数进行统计。对于需要对MySQL数据库进行操作的读者来说,本文是一个非常实用的参考资料。 ... [详细]
  • 如何优化Webpack打包后的代码分割
    本文介绍了如何通过优化Webpack的代码分割来减小打包后的文件大小。主要包括拆分业务逻辑代码和引入第三方包的代码、配置Webpack插件、异步代码的处理、代码分割重命名、配置vendors和cacheGroups等方面的内容。通过合理配置和优化,可以有效减小打包后的文件大小,提高应用的加载速度。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • c语言\n不换行,c语言printf不换行
    本文目录一览:1、C语言不换行输入2、c语言的 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
author-avatar
CJT--陳嘉婷
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有