MySQL之left join表查詢中發生字符集轉換致使表索引失效

1、出現的場景

研發leader忽然給了1條sql說這條sql在測試環境庫db-stage執行很是的慢,放到線上db-read從庫上執行很是的快。並且線上庫從庫的表的數據遠多於測試環境庫的表數據。讓我分析下是什麼問題??mysql

2、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 執行計劃中顯示的一致。
sql

3、驗證explain計劃

本覺得測試環境庫配置參數和線上db-read庫配置參數都是同樣的。研發的話不能全信。仍是拿着sql在測試庫db-stage和線上db-read1 (Mariadb庫版本10.2.17),db-read4(mysql5.7.32) 跑了下json

3.一、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,可是沒走索引,而且進行了全表掃描。ide

3.二、線上從庫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 ,並且走了索引的。oop

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.四、採用explain format=json 方式查看執行計劃

換了一種方式查看sql的執行計劃:找到了線索ui

指定explain執行計劃的線上格式爲JSON。能夠更詳細的顯示出執行計劃的具體信息(建議生產上多多使用此方法分析sql執行計劃)this

在db-stage庫上執行分析:code

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)

4、查看錶字符集肯定最終的問題

問題就是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

5、修改表字符集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的優化

相關文章
相關標籤/搜索