数据库监控与调优【十九】—— SQL调优实战

SQL调优实战

SQL调优实战1-常规调优

项目建表语句

-- ----------------------------
-- Table structure for carousel
-- ----------------------------
DROP TABLE IF EXISTS `carousel`;
CREATE TABLE `carousel`  (`id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '主键',`image_url` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '图片 图片地址',`background_color` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '背景色',`item_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '商品id 商品id',`cat_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '商品分类id 商品分类id',`type` int(0) NOT NULL COMMENT '轮播图类型 轮播图类型,用于判断,可以根据商品id或者分类进行页面跳转,1:商品 2:分类',`sort` int(0) NOT NULL COMMENT '轮播图展示顺序',`is_show` int(0) NOT NULL COMMENT '是否展示',`create_time` datetime(0) NOT NULL COMMENT '创建时间 创建时间',`update_time` datetime(0) NOT NULL COMMENT '更新时间 更新',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '轮播图 ' ROW_FORMAT = Dynamic;-- ----------------------------
-- Table structure for category
-- ----------------------------
DROP TABLE IF EXISTS `category`;
CREATE TABLE `category`  (`id` int(0) NOT NULL AUTO_INCREMENT COMMENT '主键',`name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '分类名称',`type` int(0) NOT NULL COMMENT '分类类型',`father_id` int(0) NOT NULL COMMENT '父id',`logo` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '图标',`slogan` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '口号',`cat_image` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '分类图',`bg_color` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '背景颜色',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 220073 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '商品分类 ' ROW_FORMAT = Dynamic;-- ----------------------------
-- Table structure for items
-- ----------------------------
DROP TABLE IF EXISTS `items`;
CREATE TABLE `items`  (`id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品主键id',`item_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品名称 商品名称',`cat_id` int(0) NOT NULL COMMENT '分类外键id 分类id',`root_cat_id` int(0) NOT NULL COMMENT '一级分类外键id',`sell_counts` int(0) NOT NULL COMMENT '累计销售 累计销售',`on_off_status` int(0) NOT NULL COMMENT '上下架状态 上下架状态,1:上架 2:下架',`content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品内容 商品内容',`created_time` datetime(0) NOT NULL COMMENT '创建时间',`updated_time` datetime(0) NOT NULL COMMENT '更新时间',PRIMARY KEY (`id`) USING BTREE,INDEX `items_sell_counts_item_name_index`(`sell_counts`, `item_name`) USING BTREE,INDEX `items_item_name_sell_counts_index`(`item_name`, `sell_counts`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '商品表 商品信息相关表:分类表,商品图片表,商品规格表,商品参数表' ROW_FORMAT = Dynamic;-- ----------------------------
-- Table structure for items_comments
-- ----------------------------
DROP TABLE IF EXISTS `items_comments`;
CREATE TABLE `items_comments`  (`id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'id主键',`user_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '用户id 用户名须脱敏',`item_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品id',`item_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '商品名称',`item_spec_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '商品规格id 可为空',`sepc_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '规格名称 可为空',`comment_level` int(0) NOT NULL COMMENT '评价等级 1:好评 2:中评 3:差评',`content` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '评价内容',`created_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',`updated_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '商品评价表 ' ROW_FORMAT = Dynamic;-- ----------------------------
-- Table structure for items_img
-- ----------------------------
DROP TABLE IF EXISTS `items_img`;
CREATE TABLE `items_img`  (`id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '图片主键',`item_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品外键id 商品外键id',`url` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '图片地址 图片地址',`sort` int(0) NOT NULL COMMENT '顺序 图片顺序,从小到大',`is_main` int(0) NOT NULL COMMENT '是否主图 是否主图,1:是,0:否',`created_time` datetime(0) NOT NULL COMMENT '创建时间',`updated_time` datetime(0) NOT NULL COMMENT '更新时间',PRIMARY KEY (`id`) USING BTREE,INDEX `items_img_is_main_item_id_index`(`is_main`, `item_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '商品图片 ' ROW_FORMAT = Dynamic;-- ----------------------------
-- Table structure for items_param
-- ----------------------------
DROP TABLE IF EXISTS `items_param`;
CREATE TABLE `items_param`  (`id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品参数id',`item_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品外键id',`produc_place` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '产地 产地,例:中国江苏',`foot_period` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '保质期 保质期,例:180天',`brand` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '品牌名 品牌名,例:三只大灰狼',`factory_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '生产厂名 生产厂名,例:大灰狼工厂',`factory_address` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '生产厂址 生产厂址,例:大灰狼生产基地',`packaging_method` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '包装方式 包装方式,例:袋装',`weight` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '规格重量 规格重量,例:35g',`storage_method` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '存储方法 存储方法,例:常温5~25°',`eat_method` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '食用方式 食用方式,例:开袋即食',`created_time` datetime(0) NOT NULL COMMENT '创建时间',`updated_time` datetime(0) NOT NULL COMMENT '更新时间',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '商品参数 ' ROW_FORMAT = Dynamic;-- ----------------------------
-- Table structure for items_spec
-- ----------------------------
DROP TABLE IF EXISTS `items_spec`;
CREATE TABLE `items_spec`  (`id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品规格id',`item_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品外键id',`name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '规格名称',`stock` int(0) NOT NULL COMMENT '库存',`discounts` decimal(4, 2) NOT NULL COMMENT '折扣力度',`price_discount` int(0) NOT NULL COMMENT '优惠价',`price_normal` int(0) NOT NULL COMMENT '原价',`created_time` datetime(0) NOT NULL COMMENT '创建时间',`updated_time` datetime(0) NOT NULL COMMENT '更新时间',PRIMARY KEY (`id`) USING BTREE,INDEX `price_discount_item_id_price_discount_index`(`item_id`, `price_discount`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '商品规格 每一件商品都有不同的规格,不同的规格又有不同的价格和优惠力度,规格表为此设计' ROW_FORMAT = Dynamic;-- ----------------------------
-- Table structure for order_items
-- ----------------------------
DROP TABLE IF EXISTS `order_items`;
CREATE TABLE `order_items`  (`id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '主键id',`order_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '归属订单id',`item_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品id',`item_img` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品图片',`item_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品名称',`item_spec_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '规格id',`item_spec_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '规格名称',`price` int(0) NOT NULL COMMENT '成交价格',`buy_counts` int(0) NOT NULL COMMENT '购买数量',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '订单商品关联表 ' ROW_FORMAT = Dynamic;-- ----------------------------
-- Table structure for order_status
-- ----------------------------
DROP TABLE IF EXISTS `order_status`;
CREATE TABLE `order_status`  (`order_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '订单ID;对应订单表的主键id',`order_status` int(0) NOT NULL COMMENT '订单状态',`created_time` datetime(0) NULL DEFAULT NULL COMMENT '订单创建时间;对应[10:待付款]状态',`pay_time` datetime(0) NULL DEFAULT NULL COMMENT '支付成功时间;对应[20:已付款,待发货]状态',`deliver_time` datetime(0) NULL DEFAULT NULL COMMENT '发货时间;对应[30:已发货,待收货]状态',`success_time` datetime(0) NULL DEFAULT NULL COMMENT '交易成功时间;对应[40:交易成功]状态',`close_time` datetime(0) NULL DEFAULT NULL COMMENT '交易关闭时间;对应[50:交易关闭]状态',`comment_time` datetime(0) NULL DEFAULT NULL COMMENT '留言时间;用户在交易成功后的留言时间',PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '订单状态表;订单的每个状态更改都需要进行记录\n10:待付款  20:已付款,待发货  30:已发货,待收货(7天自动确认)  40:交易成功(此时可以评价)50:交易关闭(待付款时,用户取消 或 长时间未付款,系统识别后自动关闭)\n退货/退货,此分支流程不做,所以不加入' ROW_FORMAT = Dynamic;-- ----------------------------
-- Table structure for orders
-- ----------------------------
DROP TABLE IF EXISTS `orders`;
CREATE TABLE `orders`  (`id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '订单主键;同时也是订单编号',`user_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户id',`receiver_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '收货人快照',`receiver_mobile` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '收货人手机号快照',`receiver_address` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '收货地址快照',`total_amount` int(0) NOT NULL COMMENT '订单总价格',`real_pay_amount` int(0) NOT NULL COMMENT '实际支付总价格',`post_amount` int(0) NOT NULL COMMENT '邮费;默认可以为零,代表包邮',`pay_method` int(0) NOT NULL COMMENT '支付方式',`left_msg` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '买家留言',`extand` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '扩展字段',`is_comment` int(0) NOT NULL COMMENT '买家是否评价;1:已评价,0:未评价',`is_delete` int(0) NOT NULL COMMENT '逻辑删除状态;1: 删除 0:未删除',`created_time` datetime(0) NOT NULL COMMENT '创建时间(成交时间)',`updated_time` datetime(0) NOT NULL COMMENT '更新时间',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '订单表;' ROW_FORMAT = Dynamic;-- ----------------------------
-- Table structure for stu
-- ----------------------------
DROP TABLE IF EXISTS `stu`;
CREATE TABLE `stu`  (`id` int(0) NOT NULL AUTO_INCREMENT,`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,`age` int(0) NOT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7347 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Table structure for user_address
-- ----------------------------
DROP TABLE IF EXISTS `user_address`;
CREATE TABLE `user_address`  (`id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '地址主键id',`user_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '关联用户id',`receiver` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '收件人姓名',`mobile` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '收件人手机号',`province` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '省份',`city` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '城市',`district` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '区县',`detail` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '详细地址',`extand` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '扩展字段',`is_default` int(0) NULL DEFAULT NULL COMMENT '是否默认地址',`created_time` datetime(0) NOT NULL COMMENT '创建时间',`updated_time` datetime(0) NOT NULL COMMENT '更新时间',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户地址表 ' ROW_FORMAT = Dynamic;-- ----------------------------
-- Table structure for users
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users`  (`id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键id 用户id',`username` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名 用户名',`password` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '密码 密码',`nickname` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '昵称 昵称',`realname` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '真实姓名',`face` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '头像',`mobile` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手机号 手机号',`email` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱地址 邮箱地址',`sex` int(0) NULL DEFAULT NULL COMMENT '性别 性别 1:男  0:女  2:保密',`birthday` date NULL DEFAULT NULL COMMENT '生日 生日',`created_time` datetime(0) NOT NULL COMMENT '创建时间 创建时间',`updated_time` datetime(0) NOT NULL COMMENT '更新时间 更新时间',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户表 ' ROW_FORMAT = Dynamic;

查看项目数据量

-- 174
select count(*) from items;-- 350
select count(*) from items_img;

数据量太少,很难体现出调优后的性能差异

创建存储过程

-- 关闭MySQL对存储过程的限制
set global log_bin_trust_function_creators = 0;-- 执行insert into select...,重复repeat_times次
drop procedure if exists prepare_test_data;
DELIMITER $$
CREATE PROCEDURE prepare_test_data(IN repeat_times INT(10))
BEGINDECLARE i INT DEFAULT 0;loopname:LOOPSET i = i + 1;INSERT INTO carousel (id, image_url, background_color, item_id, cat_id, type, sort, is_show,create_time, update_time)SELECT uuid(),image_url,background_color,item_id,cat_id,type,sort,is_show,create_time,update_timefrom carousel;insert into category (name, type, father_id, logo, slogan, cat_image, bg_color)select name, type, father_id, logo, slogan, cat_image, bg_colorfrom category;insert into items(id, item_name, cat_id, root_cat_id, sell_counts, on_off_status, content,created_time, updated_time)select uuid(),item_name,cat_id,root_cat_id,sell_counts,on_off_status,content,created_time,updated_timefrom items;insert into items_comments (id, user_id, item_id, item_name, item_spec_id, sepc_name, comment_level,content, created_time, updated_time)select uuid(),user_id,item_id,item_name,item_spec_id,sepc_name,comment_level,content,created_time,updated_timefrom items_comments;insert into items_img(id, item_id, url, sort, is_main, created_time, updated_time)select uuid(), item_id, url, sort, is_main, created_time, updated_timefrom items_img;insert into items_param(id, item_id, produc_place, foot_period, brand, factory_name,factory_address, packaging_method, weight, storage_method, eat_method,created_time, updated_time)select uuid(),item_id,produc_place,foot_period,brand,factory_name,factory_address,packaging_method,weight,storage_method,eat_method,created_time,updated_timefrom items_param;insert into items_spec (id, item_id, name, stock, discounts, price_discount, price_normal,created_time, updated_time)select uuid(),item_id,name,stock,discounts,price_discount,price_normal,created_time,updated_timefrom items_spec;insert into order_items (id, order_id, item_id, item_img, item_name, item_spec_id, item_spec_name,price, buy_counts)select uuid(),order_id,item_id,item_img,item_name,item_spec_id,item_spec_name,price,buy_countsfrom order_items;insert into order_status (order_id, order_status, created_time, pay_time, deliver_time,success_time, close_time, comment_time)select uuid(),order_status,created_time,pay_time,deliver_time,success_time,close_time,comment_timefrom order_status;insert into orders (id, user_id, receiver_name, receiver_mobile, receiver_address, total_amount,real_pay_amount, post_amount, pay_method, left_msg, extand, is_comment,is_delete, created_time, updated_time)select uuid(),user_id,receiver_name,receiver_mobile,receiver_address,total_amount,real_pay_amount,post_amount,pay_method,left_msg,extand,is_comment,is_delete,created_time,updated_timefrom orders;insert into stu (name, age)select name, agefrom stu;insert into user_address (id, user_id, receiver, mobile, province, city, district, detail, extand,is_default, created_time, updated_time)select uuid(),user_id,receiver,mobile,province,city,district,detail,extand,is_default,created_time,updated_timefrom user_address;insert into users(id, username, password, nickname, realname, face, mobile, email, sex, birthday,created_time, updated_time)select uuid(),username,password,nickname,realname,face,mobile,email,sex,birthday,created_time,updated_timefrom users;IF i = repeat_times THENLEAVE loopname;END IF;END LOOP loopname;
END $$;

使用存储过程生成数据

-- 把foodie-dev项目里面所有的表数据量变成原先的2^10倍
call prepare_test_data(10);

查看项目现在的数据量

-- 178176
select count(*) from items;-- 358400
select count(*) from items_img;

设置慢查询日志记录慢SQL大小

## 查看执行时间超过这么久才记录到慢查询日志,单位秒,可使用小数表示小于秒的时间
show variables like '%long_query_time%';## 设置执行时间超过这么久才记录到慢查询日志,单位秒,可使用小数表示小于秒的时间
set long_query_time = 0.2;

避免干扰清空日志文件

## 进入目录
cd /var/lib/mysql## 清空文件(> 文件名)
> es23-slow.log## 查看文件大小
ls -lh

启动项目调用搜索商品列表接口

GET http://localhost:8088/items/search?keywords=好吃蛋糕甜点蒸蛋糕&sort=c&page=1&pageSize10
Accept: application/json

可以看到这个接口肉眼可见的慢,花费1.053s

查询慢查询日志该接口执行的SQL

SELECTi.id AS itemId,i.item_name AS itemName,i.sell_counts AS sellCounts,ii.url AS imgUrl,tempSpec.price_discount AS price 
FROMitems i STRAIGHT_JOIN items_img ii ON i.id = ii.item_idLEFT JOIN ( SELECT item_id, MIN( price_discount ) AS price_discount FROM items_spec GROUP BY item_id ) tempSpec ON i.id = tempSpec.item_id 
WHEREii.is_main = 1 AND i.item_name LIKE '%好吃蛋糕甜点蒸蛋糕%' 
ORDER BYi.sell_counts DESC LIMIT 10;-- 优化之前需要花费0.437s

具体优化操作

使用EXPLAIN分析

EXPLAIN SELECTi.id AS itemId,i.item_name AS itemName,i.sell_counts AS sellCounts,ii.url AS imgUrl,tempSpec.price_discount AS price 
FROMitems iLEFT JOIN items_img ii ON i.id = ii.item_idLEFT JOIN ( SELECT item_id, MIN( price_discount ) AS price_discount FROM items_spec GROUP BY item_id ) tempSpec ON i.id = tempSpec.item_id 
WHEREii.is_main = 1 AND i.item_name LIKE '%好吃蛋糕甜点蒸蛋糕%' 
ORDER BYi.sell_counts DESC LIMIT 10;

在这里插入图片描述

优化一

由于EXPLAIN后的id存在多个值,id大的值会先执行,所以先执行这条sql

SELECT item_id, MIN( price_discount ) AS price_discount FROM items_spec GROUP BY item_id

可以看到这是一个GROUP BY语句,所以可以创建一个索引,如下

ALTER TABLE items_spec ADD INDEX price_discount_item_id_price_discount_index (item_id, price_discount);-- 优化一之后需要花费0.231s

再次执行EXPLAIN查看

在这里插入图片描述

可以发现该条SQL的type变成range,并且Extra中显示了Using index for group-by表示使用了松散索引扫描

优化二

可以看到查询ii表的type也是ALL,使用了全表扫描,根据SQL中查询需要的字段故可以创建以下索引

ALTER TABLE items_img ADD INDEX items_img_is_main_item_id_index (is_main, item_id);-- 优化二之后需要花费0.281s,反而增加了
-- 暂时不知道咋回事,但是这种优化方案是适用的!

再次执行EXPLAIN查看

在这里插入图片描述

可以发现操作ii表的SQL的type变成ref,此时已经没有全表扫描了

优化三

可以看到操作i表的SQL中只操作了字段item_name、sell_counts、id(已经有索引了),故可以为这两个字段创建组合索引,希望覆盖i表上面的所有字段

ALTER TABLE items ADD INDEX items_sell_counts_item_name_index (sell_counts, item_name);

但是由于是先扫描了ii表再扫描i表,而i表和ii表的关系是通过ON i.id = ii.item_id关联的,因此只会使用i表的主键

要想使用i表上面的组合索引,就需要把两张表的连接方式由LEFT JOIN改为STRAIGHT_JOIN,强制使用i表作为驱动表

再次执行EXPLAIN查看

EXPLAIN SELECTi.id AS itemId,i.item_name AS itemName,i.sell_counts AS sellCounts,ii.url AS imgUrl,tempSpec.price_discount AS price 
FROMitems i STRAIGHT_JOIN items_img ii ON i.id = ii.item_idLEFT JOIN ( SELECT item_id, MIN( price_discount ) AS price_discount FROM items_spec GROUP BY item_id ) tempSpec ON i.id = tempSpec.item_id 
WHEREii.is_main = 1 AND i.item_name LIKE '%好吃蛋糕甜点蒸蛋糕%' 
ORDER BYi.sell_counts DESC LIMIT 10;

在这里插入图片描述

可以看到type是index,key是items_sell_counts_item_name_index,表示使用了刚刚创建的索引items_sell_counts_item_name_index,而且Extra中显示Using index表示使用了覆盖索引

另外,Extra中还显示Backward index scan;是MySQL8.0的优化表示从索引的后面往前面扫描,因为这里ORDER BY i.sell_counts DESC,而刚刚创建的索引没有指定排序,默认情况下ASC。如果MySQL版本大于等于8.0,可以修改该索引为降序排序提升性能(降序索引是MySQL8.0之后支持的,之前语法支持,效果不支持)

ALTER TABLE items ADD INDEX items_sell_counts_item_name_index (sell_counts DESC, item_name) ;

再次执行EXPLAIN查看

在这里插入图片描述

再次执行sql查看运行耗时可以发现只花费了0.01s

修改SQL一(应对多种排序规则)
SELECTi.id AS itemId,i.item_name AS itemName,i.sell_counts AS sellCounts,ii.url AS imgUrl,tempSpec.price_discount AS price 
FROMitems i STRAIGHT_JOIN items_img ii ON i.id = ii.item_idLEFT JOIN ( SELECT item_id, MIN( price_discount ) AS price_discount FROM items_spec GROUP BY item_id ) tempSpec ON i.id = tempSpec.item_id 
WHEREii.is_main = 1 AND i.item_name LIKE '%好吃蛋糕甜点蒸蛋糕%' 
ORDER BYi.item_name ASC LIMIT 10;-- 此时需要0.041s
优化方案

在之前优化的基础上,再额外给items表添加一个索引

ALTER TABLE items ADD INDEX items_item_name_sell_counts_index (item_name, sell_counts) ;

再次执行发现只需要0.027s

修改SQL二(应对多种排序规则)
SELECTi.id AS itemId,i.item_name AS itemName,i.sell_counts AS sellCounts,ii.url AS imgUrl,tempSpec.price_discount AS price 
FROMitems i STRAIGHT_JOIN items_img ii ON i.id = ii.item_idLEFT JOIN ( SELECT item_id, MIN( price_discount ) AS price_discount FROM items_spec GROUP BY item_id ) tempSpec ON i.id = tempSpec.item_id 
WHEREii.is_main = 1 AND i.item_name LIKE '%好吃蛋糕甜点蒸蛋糕%' 
ORDER BYtempSpec.price_discount ASC LIMIT 10;-- 此时需要0.218s
优化方案一

执行EXPLAIN查看

在这里插入图片描述

可以看到操作i表的Extra中出现了Using filesort,故可以参考前面的优化方案优化

比如

-- 调大sort_buffer_size -> 145ms
set sort_buffer_size = 4 * 1024 * 1024;-- 再次执行上面的SQL语句,可以发现花费了0.052s
优化方案二

终极优化方案:反模式设计,引入冗余,把商品的最低优惠价(MIN(price_discount))冗余到items表

这样的好处:SELECT item_id, MIN( price_discount ) AS price_discount FROM items_spec GROUP BY item_idzh这个子查询不需要了。sql简单了。同时排序也可以使用索引,后续优化这条sql也要简单很多

总结
  • 如何阅读EXPLAIN结果
  • 利用松散索引扫描优化GROUP BY
  • 利用STRAIGHT_JOIN强制指定JOIN的顺序
  • 利用索引避免排序

SQL调优实战2-激进调优

SELECTi.id AS itemId,i.item_name AS itemName,i.sell_counts AS sellCounts,ii.url AS imgUrl,tempSpec.price_discount AS price 
FROMitems i STRAIGHT_JOIN items_img ii ON i.id = ii.item_idLEFT JOIN ( SELECT item_id, MIN( price_discount ) AS price_discount FROM items_spec GROUP BY item_id ) tempSpec ON i.id = tempSpec.item_id 
WHEREii.is_main = 1 AND i.item_name LIKE '%好吃蛋糕甜点蒸蛋糕%' 
ORDER BYi.sell_counts DESCLIMIT 10;

激进优化方案一

我们知道,全模糊是用不了索引的,而右模糊是可以使用索引的。因此,如果业务上允许的话,尽量使用右模糊,避免全模糊

注意:

代码中的sql写法

<select id="searchItems" parameterType="Map" resultType="com.imooc.pojo.vo.SearchItemsVO">SELECTi.id as itemId,i.item_name as itemName,i.sell_counts as sellCounts,ii.url as imgUrl,tempSpec.price_discount as priceFROMitems iLEFT JOINitems_img iioni.id = ii.item_idLEFT JOIN(SELECT item_id, MIN(price_discount) as price_discount FROM items_spec GROUP BY item_id) tempSpeconi.id = tempSpec.item_idWHEREii.is_main = 1<if test=" paramsMap.keywords != null and paramsMap.keywords != '' ">AND i.item_name like '%${paramsMap.keywords}%' /*两个%因为要拼接到paramsMap.keywords里,所以必须使用$,不能使用#*/</if>order by<choose><when test=" paramsMap.sort == &quot;c&quot; ">i.sell_counts desc</when><when test=" paramsMap.sort == &quot;p&quot; ">tempSpec.price_discount asc</when><otherwise>i.item_name asc</otherwise></choose>
</select>

可以看到like写法是like '%${paramsMap.keywords}%'

$符号是字符串替换符,就引发sql注入,比如传入xxx%'; drop table users; select * from items where item_name like 'yyy%

这样sql就变成了

SELECTi.id AS itemId,i.item_name AS itemName,i.sell_counts AS sellCounts,ii.url AS imgUrl,tempSpec.price_discount AS price 
FROMitems i STRAIGHT_JOIN items_img ii ON i.id = ii.item_idLEFT JOIN ( SELECT item_id, MIN( price_discount ) AS price_discount FROM items_spec GROUP BY item_id ) tempSpec ON i.id = tempSpec.item_id 
WHEREii.is_main = 1 AND i.item_name LIKE 'xxx%'; drop table users; select * from items where item_name like 'yyy%' 
ORDER BYi.sell_counts DESCLIMIT 10;

直接删除了users表,风险巨大!

可以修改为

<select id="searchItems" parameterType="Map" resultType="com.imooc.pojo.vo.SearchItemsVO">SELECTi.id as itemId,i.item_name as itemName,i.sell_counts as sellCounts,ii.url as imgUrl,tempSpec.price_discount as priceFROMitems iLEFT JOINitems_img iioni.id = ii.item_idLEFT JOIN(SELECT item_id, MIN(price_discount) as price_discount FROM items_spec GROUP BY item_id) tempSpeconi.id = tempSpec.item_idWHEREii.is_main = 1<if test=" paramsMap.keywords != null and paramsMap.keywords != '' ">AND i.item_name like CONCAT('%', #{paramsMap.keywords}, '%')</if>order by<choose><when test=" paramsMap.sort == &quot;c&quot; ">i.sell_counts desc</when><when test=" paramsMap.sort == &quot;p&quot; ">tempSpec.price_discount asc</when><otherwise>i.item_name asc</otherwise></choose>
</select>

激进优化方案二

彻底使用冗余优化SQL

具体操作:

– 把商品的最低优惠价,直接冗余到items表
– 把商品主图也冗余到items表【商品主图字段较大,实际项目中如果要冗余较大的字段,应该谨慎考虑,看是否有必要】

即在item表新增字段price_discount,和img_url,最后sql可以优化为如下,直接是单表查询了

SELECTid,item_name,sell_counts,img_url,price_discount 
FROMitems 
WHEREitem_name LIKE '%好吃蛋糕甜点蒸蛋糕%' 
ORDER BYsell_counts DESC

注意:冗余也不是万能方案,滥用的话在数据增删改时会比较麻烦

激进优化方案三

考虑使用非关系型数据库(elasticsearch/mongodb)

对于商品这样的业务,不需要严格的事务支持,但是性能却是硬需求,因此可以存储到非关系型数据库(elasticsearch/mongodb)

注意:引用非关系型数据库(elasticsearch/mongodb)也不是万能方案,会带来额外的学习成本、使用成本、运维成本

但是就目前来说,各种非关系型数据库正在变得越来越流行,并且电商项目中的商品中心大多数就是使用elasticsearch存储数据的,需要根据业务场景选择合适的数据库

激进优化方案四

业务妥协

业务妥协可以把比较难优化的问题变成不是问题

比如,如果业务能够接受不展示最低优惠价,子查询SELECT item_id, MIN(price_discount) as price_discount from items_spec GROUP BY item_id可以直接不要。变成两表连接查询。当然,此场景不可能不展示最低优惠价

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/726.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023年上半年部分团队的总结

&#xff08;目前还是草稿版本&#xff09; 写作&#xff0c;慢思考&#xff1a; 软件团队每天有繁忙的工作&#xff0c;有很多待办事项&#xff0c;会议&#xff0c;口头交流&#xff0c;线上的 bug 要处理&#xff0c;报表要生成和解释… … 一个月过去了&#xff0c;正想总…

【YOLO】目标识别模型的导出和opencv部署

文章目录 0 前期教程1 什么是模型部署2 怎么部署 0 前期教程 【YOLO】朴实无华的yolov5环境配置 【YOLO】yolov5训练自己的数据集 1 什么是模型部署 前期教程当中&#xff0c;介绍了yolov5环境的搭建以及如何利用yolov5进行模型训练和测试&#xff0c;虽然能够实现图片或视频…

同一 tomcat 不同项目 session 共享实现

说明 这里仅讨论 同一个tomcat&#xff0c;部署了两个工程&#xff08;两个war包&#xff09;。不涉及不同tomcat,不涉及集群 背景 tomcat中的工程A包含用户登录、退出、权限控制等功能&#xff1b;工程B包含业务功能接口。工程A将用户登录信息加密响应给前端&#xff0c;前…

【树莓派】解密树莓派Python项目中神秘的导入错误

文章目录 问题导入python文件目录分析解决方案 问题导入 小编在使用树莓派编写python项目时出现了以下两种错误&#xff1a; ModuleNotFoundError : No module named Motor from ..hardware.motor import Motor portError: attempted relative import with no known parent p…

Python 进阶(三):Python使用ORM框架SQLAlchemy操作Oracle数据库

Python使用ORM框架SQLAlchemy操作Oracle数据库 前言1. 安装Oracle Instant Client2. 安装依赖库3. 导入模块并创建引擎4. 操作oracle数据库4.1 新增数据4.2 查询数据4.3 更新数据4.4 删除数据 前言 要详细连接Oracle数据库并使用SQLAlchemy进行操作&#xff0c;按照以下步骤进…

欧科云链在GEF论坛发起圆桌:监管科技与Web3合规发展图景与展望

6月15日&#xff0c;欧科云链在格林威治经济论坛发起了一场题为“监管科技与Web3合规发展图景与展望”的圆桌会议&#xff0c;此次会议由中国香港贸易发展局副执行董事PatrickLau博士主持。Stratford Finance首席执行官Angelina Kwan&#xff0c;BC科技集团有限公司董事会副主席…

【spring cloud学习】4、创建服务提供者

注册中心Eureka Server创建并启动之后&#xff0c;接下来介绍如何创建一个Provider并且注册到Eureka Server中&#xff0c;再提供一个REST接口给其他服务调用。 首先一个Provider至少需要两个组件包依赖&#xff1a;Spring Boot Web服务组件和Eureka Client组件。如下所示&…

功能测试的技术

目录 前言&#xff1a; 1) 基于最终用户/系统测试 2) 等价测试 3) 边界值测试 4) 基于决策的测试 5) 备用流量测试 6) 临时测试 前言&#xff1a; 功能测试是软件测试中最常见的一种测试类型&#xff0c;它旨在验证系统的功能是否符合设计要求和预期行为。在进行功能测…

HackTheBox - 学院【CPTS】复习1 - PASSWORD ATTACKS

前言 有一个月时间没发文章了&#xff0c;我在6月11号进入htb学院学习CPTS&#xff0c;在扎实的THM基础的加持下&#xff0c;我学的非常顺利&#xff0c;其实大部分内容都相当于复习&#xff0c;而学到的内容只是一些可能不太常见、又或者非常细节的小技巧&#xff0c;这也是非…

【Visual Studio】Qt 获取系统时间,并实时更新时间,使用 C++ 语言,配合 Qt 开发串口通信界面

知识不是单独的&#xff0c;一定是成体系的。更多我的个人总结和相关经验可查阅这个专栏&#xff1a;Visual Studio。 这个需求来源于这个工程&#xff1a;【Visual Studio】Qt 的实时绘图曲线功能&#xff0c;使用 C 语言&#xff0c;配合 Qt 开发串口通信界面。 文章目录 Qt…

PHP 税务申报征收系统mysql数据库web结构apache计算机软件工程网页wamp

一、源码特点 PHP 税务申报征收系统 是一套完善的WEB设计系统&#xff0c;对理解php编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 代码下载 https://download.csdn.net/download/qq_41221322/87959340https://downl…

【数据库】MySQL主从同步失败或重启后需要重新配置同步,主从同步延迟解决方案,mysql主从同步加速

最近在学习MySQL&#xff0c;主从同步方案。由于是新手&#xff0c;如有出现错误的地方&#xff0c;请大家谅解并留言指正。MySQL不同的版本配置稍有不同&#xff0c;最新版本8.0.27是默认开启binarylog的&#xff0c;见下图 查询MySQL信息 SELECT version,NOW() ;show variabl…