订单的表结构采用了垂直分表的策略,将订单相关的不同模块的字段维护在不同表中

在订单处理这个页面,需要查询各种维度,

因此为了方便查询创建了v_sale_order视图(老版本)

drop view v_sale_order;
CREATE
VIEW `v_sale_order` AS
SELECT
`so`.`sale_order_id` AS `v_sale_order_id`,
`so`.`sale_order_id` AS `sale_order_id`,
`so`.`sale_order_no` AS `sale_order_no`,
`so`.`order_type` AS `order_type`,
`so`.`platform_order_code2` AS `platform_order_code2`,
`so`.`platform_order_code` AS `platform_order_code`,
`so`.`platform_type` AS `platform_type`,
`so`.`platform_order_status` AS `platform_order_status`,
`so`.`created` AS `created`,
`so`.`end_time` AS `end_time`,
`so`.`total_num` AS `total_num`,
`so`.`total_sku` AS `total_sku`,
`so`.`modified` AS `modified`,
`so`.`seller_flag` AS `seller_flag`,
`so`.`seller_memo` AS `seller_memo`,
`so`.`seller_rate` AS `seller_rate`,
`so`.`snapshot_url` AS `snapshot_url`,
`so`.`status` AS `status`,
`so`.`step_trade_status` AS `step_trade_status`,
`so`.`trade_from` AS `trade_from`,
`so`.`trade_memo` AS `trade_memo`,
`so`.`trade_source` AS `trade_source`,
`so`.`type` AS `type`,
`so`.`shop_id` AS `shop_id`,
`so`.`origin_type` AS `origin_type`,
`so`.`sys_promotion_info` AS `sys_promotion_info`,
`sor`.`buyer_area` AS `buyer_area`,
`sor`.`buyer_email` AS `buyer_email`,
`sor`.`buyer_ip` AS `buyer_ip`,
`sor`.`buyer_memo` AS `buyer_memo`,
`sor`.`buyer_message` AS `buyer_message`,
`sor`.`buyer_nick` AS `buyer_nick`,
`sor`.`buyer_rate` AS `buyer_rate`,
`sor`.`receiver_address` AS `receiver_address`,
`sor`.`receiver_city` AS `receiver_city`,
`sor`.`receiver_country` AS `receiver_country`,
`sor`.`receiver_district` AS `receiver_district`,
`sor`.`receiver_mobile` AS `receiver_mobile`,
`sor`.`receiver_name` AS `receiver_name`,
`sor`.`receiver_phone` AS `receiver_phone`,
`sor`.`receiver_state` AS `receiver_state`,
`sor`.`receiver_town` AS `receiver_town`,
`sor`.`receiver_zip` AS `receiver_zip`,
`sor`.`area_id` AS `area_id`,
`sor`.`customer_id` AS `customer_id`,
`soc`.`courier_id` AS `courier_id`,
`soc`.`courier_order_no` AS `courier_order_no`,
`soc`.`courier_print_mark_state` AS `courier_print_mark_state`,
`soc`.`courier_print_time` AS `courier_print_time`,
`sof`.`alipay_id` AS `alipay_id`,
`sof`.`alipay_no` AS `alipay_no`,
`sof`.`payment` AS `payment`,
`sof`.`total_fee` AS `total_fee`,
`soi`.`invoice_order_no` AS `invoice_order_no`,
`soi`.`invoice_content` AS `invoice_content`,
`soi`.`invoice_type` AS `invoice_type`,
`soi`.`bank` AS `bank`,
`soi`.`title` AS `title`,
`soi`.`bank_account` AS `bank_account`,
`soi`.`tariff_lines` AS `tariff_lines`,
`sos`.`oms_process_type` AS `oms_process_type`,
`sos`.`play_state` AS `play_state`,
`sos`.`pause_state` AS `pause_state`,
`sos`.`stop_state` AS `stop_state`,
`sos`.`archive_state` AS `archive_state`,
`sos`.`is_paid` AS `is_paid`,
`sos`.`is_checked` AS `is_checked`,
`sos`.`is_approved` AS `is_approved`,
`sos`.`is_suspended` AS `is_suspended`,
`sos`.`is_invalidated` AS `is_invalidated`,
`sos`.`is_to_be_shipped` AS `is_to_be_shipped`,
`sos`.`is_after_sale` AS `is_after_sale`,
`sos`.`is_split` AS `is_split`,
`sos`.`is_combined` AS `is_combined`,
`sos`.`is_closed` AS `is_closed`,
`sos`.`is_after_sale_closed` AS `is_after_sale_closed`,
`sos`.`is_amount_changed` AS `is_amount_changed`,
`sos`.`is_part_changed` AS `is_part_changed`,
`sos`.`is_out_of_stock` AS `is_out_of_stock`,
`sos`.`pay_type` AS `pay_type`,
`sos`.`pay_time` AS `pay_time`,
`sos`.`original_order_id` AS `original_order_id`,
`sos`.`after_sale_note` AS `after_sale_note`,
`sos`.`suspend_note` AS `suspend_note`,
`sos`.`unapprove_note` AS `unapprove_note`,
`sos`.`after_sale_type` AS `after_sale_type`,
`sos`.`blacklist_type` AS `blacklist_type`,
`sow`.`warehouse_id` AS `warehouse_id`,
`sow`.`retry_num` AS `retry_num`,
`sow`.`out_warehouse_time` AS `out_warehouse_time`,
`sow`.`purchase_order_no` AS `purchase_order_no`,
`sow`.`purchase_order_id` AS `purchase_order_id`,
`sow`.`wms_order_state` AS `wms_order_state`,
`sow`.`checked_time` AS `checked_time`,
`so`.`creator` AS `creator`,
`so`.`create_time` AS `create_time`,
`so`.`last_updater` AS `last_updater`,
`so`.`last_update_time` AS `last_update_time`,
`so`.`is_usable` AS `is_usable`,
`so`.`tenant_id` AS `tenant_id`
FROM
(
(
(
(
(
(
`sale_order` `so`
LEFT JOIN `sale_order_receiver` `sor` ON (
(
`so`.`sale_order_id` = `sor`.`sale_order_id`
)
)
)
LEFT JOIN `sale_order_status` `sos` ON (
(
`so`.`sale_order_id` = `sos`.`sale_order_id`
)
)
)
LEFT JOIN `sale_order_warehouse` `sow` ON (
(
`so`.`sale_order_id` = `sow`.`sale_order_id`
)
)
)
LEFT JOIN `sale_order_courier` `soc` ON (
(
`so`.`sale_order_id` = `soc`.`sale_order_id`
)
)
)
LEFT JOIN `sale_order_invoice` `soi` ON (
(
`so`.`sale_order_id` = `soi`.`sale_order_id`
)
)
)
LEFT JOIN `sale_order_finance` `sof` ON (
(
`so`.`sale_order_id` = `sof`.`sale_order_id`
)
)
);

之前的代码(老版本):

@Service
public class OrderService extends TemplateService { public static final String DEFALUT_FILTER = " AND NOT(is_split = 1 AND archive_state=3) AND NOT(is_combined = 1 AND archive_state=4) " +
" AND NOT(oms_process_type =0) AND (v_sale_order.platform_order_status != 'TRADE_FINISHED' OR origin_type=2) " +
"AND NOT is_invalidated=1" +
" AND NOT archive_state=5 AND NOT archive_state=6";
public static final String HISTORY_FILTER = " AND NOT(is_split = 1 AND archive_state=3) AND NOT(is_combined = 1 AND archive_state=4) " +
        " AND NOT archive_state=5 AND NOT archive_state=6"; }

DEFAULT_FILTER是订单处理里面,固定的查询条件,每次查询都会有该部分条件,但是sql的写法包含了太多OR,NOT,!= 等操作

优化第一步:  根据业务规则合并一些字段,将一些排除条件改为正向命中的条件(第二版):

@Service
public class OrderService extends TemplateService { /**
订单处理:
过滤掉:合并拆分的订单
过滤掉:交易完成或交易关闭
要求:跑过预处理
要求:已付款或者货到付款
要求:未作废的
*/
public static final String DEFALUT_FILTER = " AND archive_state IN (0, 1) AND v_sale_order.is_paid = 1 AND oms_process_type = 1 " +
" AND v_sale_order.is_invalidated=0 AND is_closed = 0";
/**
* 订单查询:
* 过滤掉:合并拆分的订单
*/
public static final String HISTORY_FILTER = " AND archive_state IN (0, 1)";
public static final String AFTER_FILTER = " AND archive_state IN (0,1,2) AND is_paid=1";
}

优化第二步:   订单处理相比订单查询多了很多固定条件,大部分处于sale_order_status表中,但是之前视图的创建方式固定了最左边的表,因此修改视图创建的脚本,如下:

从固定的left join改为 Join

CREATE OR REPLACE VIEW v_sale_order AS
SELECT
`so`.`sale_order_id` AS `v_sale_order_id`,
`so`.`sale_order_id` AS `sale_order_id`,
`so`.`sale_order_no` AS `sale_order_no`,
`so`.`order_type` AS `order_type`,
`so`.`platform_order_code2` AS `platform_order_code2`,
`so`.`platform_order_code` AS `platform_order_code`,
`so`.`platform_type` AS `platform_type`,
`so`.`platform_order_status` AS `platform_order_status`,
`so`.`created` AS `created`,
`so`.`end_time` AS `end_time`,
`so`.`total_num` AS `total_num`,
`so`.`total_sku` AS `total_sku`,
`so`.`modified` AS `modified`,
`so`.`seller_flag` AS `seller_flag`,
`so`.`seller_memo` AS `seller_memo`,
`so`.`seller_rate` AS `seller_rate`,
`so`.`snapshot_url` AS `snapshot_url`,
`so`.`status` AS `status`,
`so`.`step_trade_status` AS `step_trade_status`,
`so`.`trade_from` AS `trade_from`,
`so`.`trade_memo` AS `trade_memo`,
`so`.`trade_source` AS `trade_source`,
`so`.`type` AS `type`,
`so`.`shop_id` AS `shop_id`,
`so`.`origin_type` AS `origin_type`,
`so`.`sys_promotion_info` AS `sys_promotion_info`,
`sor`.`buyer_area` AS `buyer_area`,
`sor`.`buyer_email` AS `buyer_email`,
`sor`.`buyer_ip` AS `buyer_ip`,
`sor`.`buyer_memo` AS `buyer_memo`,
`sor`.`buyer_message` AS `buyer_message`,
`sor`.`buyer_nick` AS `buyer_nick`,
`sor`.`buyer_rate` AS `buyer_rate`,
`sor`.`receiver_address` AS `receiver_address`,
`sor`.`receiver_city` AS `receiver_city`,
`sor`.`receiver_country` AS `receiver_country`,
`sor`.`receiver_district` AS `receiver_district`,
`sor`.`receiver_mobile` AS `receiver_mobile`,
`sor`.`receiver_name` AS `receiver_name`,
`sor`.`receiver_phone` AS `receiver_phone`,
`sor`.`receiver_state` AS `receiver_state`,
`sor`.`receiver_town` AS `receiver_town`,
`sor`.`receiver_zip` AS `receiver_zip`,
`sor`.`area_id` AS `area_id`,
`sor`.`customer_id` AS `customer_id`,
`soc`.`courier_id` AS `courier_id`,
`soc`.`courier_order_no` AS `courier_order_no`,
`soc`.`courier_print_mark_state` AS `courier_print_mark_state`,
`soc`.`courier_print_time` AS `courier_print_time`,
`sof`.`alipay_id` AS `alipay_id`,
`sof`.`alipay_no` AS `alipay_no`,
`sof`.`payment` AS `payment`,
`sof`.`total_fee` AS `total_fee`,
`soi`.`invoice_order_no` AS `invoice_order_no`,
`soi`.`invoice_content` AS `invoice_content`,
`soi`.`invoice_type` AS `invoice_type`,
`soi`.`bank` AS `bank`,
`soi`.`title` AS `title`,
`soi`.`bank_account` AS `bank_account`,
`soi`.`tariff_lines` AS `tariff_lines`,
`sos`.`oms_process_type` AS `oms_process_type`,
`sos`.`play_state` AS `play_state`,
`sos`.`pause_state` AS `pause_state`,
`sos`.`stop_state` AS `stop_state`,
`sos`.`archive_state` AS `archive_state`,
`sos`.`is_paid` AS `is_paid`,
`sos`.`is_checked` AS `is_checked`,
`sos`.`is_approved` AS `is_approved`,
`sos`.`is_suspended` AS `is_suspended`,
`sos`.`is_invalidated` AS `is_invalidated`,
`sos`.`is_to_be_shipped` AS `is_to_be_shipped`,
`sos`.`is_after_sale` AS `is_after_sale`,
`sos`.`is_split` AS `is_split`,
`sos`.`is_combined` AS `is_combined`,
`sos`.`is_closed` AS `is_closed`,
`sos`.`is_after_sale_closed` AS `is_after_sale_closed`,
`sos`.`is_amount_changed` AS `is_amount_changed`,
`sos`.`is_part_changed` AS `is_part_changed`,
`sos`.`is_out_of_stock` AS `is_out_of_stock`,
`sos`.`pay_type` AS `pay_type`,
`sos`.`pay_time` AS `pay_time`,
`sos`.`original_order_id` AS `original_order_id`,
`sos`.`after_sale_note` AS `after_sale_note`,
`sos`.`suspend_note` AS `suspend_note`,
`sos`.`unapprove_note` AS `unapprove_note`,
`sos`.`after_sale_type` AS `after_sale_type`,
`sos`.`blacklist_type` AS `blacklist_type`,
`sow`.`warehouse_id` AS `warehouse_id`,
`sow`.`retry_num` AS `retry_num`,
`sow`.`out_warehouse_time` AS `out_warehouse_time`,
`sow`.`purchase_order_no` AS `purchase_order_no`,
`sow`.`purchase_order_id` AS `purchase_order_id`,
`sow`.`wms_order_state` AS `wms_order_state`,
`sow`.`checked_time` AS `checked_time`,
`so`.`creator` AS `creator`,
`sos`.`create_time` AS `create_time`,
`so`.`last_updater` AS `last_updater`,
`sos`.`last_update_time` AS `last_update_time`,
`sos`.`is_usable` AS `is_usable`,
`sos`.`tenant_id` AS `tenant_id`
FROM ((((((`sale_order_status` `sos`
JOIN `sale_order_receiver` `sor` ON ((`sos`.`sale_order_id` = `sor`.`sale_order_id`))) JOIN
`sale_order` `so` ON ((`so`.`sale_order_id` = `sos`.`sale_order_id`))) JOIN
`sale_order_warehouse` `sow` ON ((`sos`.`sale_order_id` = `sow`.`sale_order_id`))) JOIN
`sale_order_courier` `soc` ON ((`sos`.`sale_order_id` = `soc`.`sale_order_id`))) JOIN
`sale_order_finance` `sof` ON ((`sos`.`sale_order_id` = `sof`.`sale_order_id`))) LEFT JOIN
`sale_order_invoice` `soi` ON ((`sos`.`sale_order_id` = `soi`.`sale_order_id`)))

最左边表可根据查询条件动态的变化,(如条件过滤查询sale_order_courier的courier_id字段, where courier_id= xx,并且sale_order_courier的courier_id字段上已经建立了索引,那么explain后第一个查询的表就是sale_order_courier)

之前sale_order表始终作为v_sale_order实际查询时的第一个表,而无法走索引

(P.S.本人目前的理解:mysql多表关联查询只有最左边表可以走索引,其余表的索引只能是关联的id作为索引)

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE sos ref idx_sale_order_id,oms_normal_v2,oms_check_v2,oms_suspend_v2 oms_check_v2 10 const,const,const,const 271 Using where; Using filesort
1 SIMPLE sor ref idx_sale_order_id idx_sale_order_id 9 egenie.sos.sale_order_id 1 NULL
1 SIMPLE soc ref idx_sale_order_id idx_sale_order_id 9 egenie.sos.sale_order_id 1 NULL
1 SIMPLE sof ref idx_sale_order_id idx_sale_order_id 9 egenie.sos.sale_order_id 1 NULL
1 SIMPLE so eq_ref PRIMARY PRIMARY 8 egenie.sos.sale_order_id 1 NULL
1 SIMPLE sow ref idx_sale_order_id idx_sale_order_id 9 egenie.sos.sale_order_id 1 NULL
1 SIMPLE soi ref idx_sale_order_id idx_sale_order_id 9 egenie.sos.sale_order_id 1 NULL

随后创建的索引(第一版),生效

--archive_state in()结果太多 走不了索引
CREATE INDEX oms_normal on sale_order_status(tenant_id,is_usable,is_paid,oms_process_type,is_invalidated,is_closed,last_update_time); CREATE INDEX oms_check on sale_order_status(tenant_id,is_usable,is_paid,oms_process_type,is_invalidated,is_closed,
is_checked,last_update_time); CREATE INDEX oms_suspend on sale_order_status(tenant_id,is_usable,is_paid,oms_process_type,is_invalidated,is_closed,
is_suspended,last_update_time); --sale_order
CREATE INDEX shop_idx on sale_order(shop_id,order_type);
CREATE INDEX platform_idx on sale_order(platform_order_status,order_type); --sale_order_warehouse
CREATE INDEX warehouse_idx on sale_order_warehouse(warehouse_id); --sale_order_courier
CREATE INDEX courier_idx on sale_order_courier(courier_id);

由于有新需求需要改造固定的查询sql(第三版)

@Service
public class OrderService extends TemplateService { private static final String isPaySql = " AND (is_paid = 1 OR pay_type = 4 ) ";
/**
* 订单处理:
* 过滤掉:合并拆分的订单
* 过滤掉:交易完成或交易关闭
* 要求:跑过预处理
* 要求:已付款或者货到付款
* 要求:未作废的
*/
public static final String DEFALUT_FILTER = " AND archive_state IN (0, 1) AND oms_process_type = 1 " +
isPaySql + " AND v_sale_order.is_invalidated=0 AND is_closed = 0";
/**
* 订单查询:
* 过滤掉:合并拆分的订单
*/
public static final String HISTORY_FILTER = " AND archive_state IN (0, 1)";
public static final String AFTER_FILTER = " AND archive_state IN (0,1,2) " + isPaySql;
}

改进:

1.将之前的is_paid 移除之前的索引

2.调整索引的顺序,移除毫无辨识度的字段

(第二版)

CREATE INDEX oms_normal_v2 on sale_order_status(tenant_id,is_closed,oms_process_type,is_invalidated,last_update_time);

CREATE INDEX oms_check_v2 on sale_order_status(tenant_id,is_closed,oms_process_type,is_invalidated,is_checked,last_update_time);

CREATE INDEX oms_suspend_v2 on sale_order_status(tenant_id,is_closed,oms_process_type,is_invalidated,is_suspended,last_update_time);

Q&A:

1.MySQL视图可以用索引吗?

我想答案是肯定的,其索引是建立在视图后面的真实表上,而不是建立在视图上.

索引是存放在模式(schema)中的一个数据库对象,索引的作用就是提高对表的检索查询速度,索引是通过快速访问的方法来进行快速定位数据,从而减少了对磁盘的读写操作。索引是数据库的一个对象,它不能独立存在,必须对某个表对象进行依赖。

视图就是一个表或多个表的查询结果,它是一张虚拟的表,因为它并不能存储数据。

mysql优化---订单查询优化:视图优化+索引创建的更多相关文章

  1. mysql优化---订单查询优化(1):视图优化+索引创建

    订单的表结构采用了垂直分表的策略,将订单相关的不同模块的字段维护在不同表中 在订单处理这个页面,需要查询各种维度, 因此为了方便查询创建了v_sale_order视图(老版本) drop view v ...

  2. Mysql基本查询、视图、索引、触发器

    基本查询 1.修改String sql="update smbms_user set userCode=?,userName=? where id=?"; 2.删除用户String ...

  3. mysql优化---订单查询优化:异步分页处理

    订单分页查询: 老的代码是顺序执行查询数据和计算总记录数,但是如果条件复杂的话(比如关联子表)查询的时间要超过20s种 public static PagedList<Map<String ...

  4. mysql优化---订单查询优化(2):异步分页处理

    订单分页查询: 老的代码是顺序执行查询数据和计算总记录数,但是如果条件复杂的话(比如关联子表)查询的时间要超过20s种 public static PagedList<Map<String ...

  5. Mysql的事务、视图、索引、备份和恢复

    事务 事务是作为单个逻辑工作单元执行的一系列操作,一个逻辑工作单元必须具备四个属性.即:原子性.一致性.隔离性.持久性,这些特性通常简称为ACID.   原子性(Atomicity) 事务是不可分割的 ...

  6. MySQL数据库 : 自关联,视图,事物,索引

    自关联查询(自身id关联自身id(主键),查询的时候可以逻辑分为两个表,然后分别起一个别名来区分) select * from areas as cityinner join areas as pro ...

  7. mysql 优化实例之索引创建

    mysql 优化实例之索引创建 优化前: pt-query-degist分析结果: # Query 23: 0.00 QPS, 0.00x concurrency, ID 0x78761E301CC7 ...

  8. Mysql单表访问方法,索引合并,多表连接原理,基于规则的优化,子查询优化

    参考书籍<mysql是怎样运行的> 非常推荐这本书,通俗易懂,但是没有讲mysql主从等内容 书中还讲解了本文没有提到的子查询优化内容, 本文只总结了常见的子查询是如何优化的 系列文章目录 ...

  9. MySQL的or/in/union与索引优化

    转载自:MySQL的or/in/union与索引优化 https://blog.csdn.net/zhangweiwei2020/article/details/80005590 假设订单业务表结构为 ...

随机推荐

  1. Hibernate总结(二)

    在上一篇Hibernate总结(一)简单总结了一级缓存,快照,增删改查的简单使用,这一篇总结两张表的级联操作. 级联涉及到三种情况,many-many,1-many,many-1. 首先是1-many ...

  2. 通过jQuery的比较来认识AngularJS

    通过jQuery的比较来认识AngularJS 这一章主要是通过几个例子分别通过jQuery和AngularJS来达到效果.主要通过思维转换来进一步了解AngularJS框架设计背后的思想. 注意: ...

  3. Array数组基础

    数组的定义 数组(array)是按次序排列的一组值,单个值称为元素,它们的位置都有编号(从0开始).整个数组用方括号表示. var arr = ['a', 'b', 'c']; 上面代码中的a.b.c ...

  4. nginx+uwsgi 部署 django

    预装:nginx,  django Django站点tree |Site |-----Blog(自建的项目) |-----Manage.py |-----Site(setting url wsgi-. ...

  5. selenium启动firefox时加载扩展

    有些时候,我们测试需要用到插件或者已经导入的证书(比如金融和安全加密行业),而selenium启动firefox时会打开一个新的,不含有任何插件和个人证书的firefox(等同于全新安装后第一次打开的 ...

  6. Nuget很慢,我们该怎么办

    在VS中给项目添加程序已经采用NuGet 十分方便 不过很多时候速度很慢,一直显示“正在检索信息” 其实直接使用程序包管理控制台,速度就会好很多 如果命令不太会写,安装包名不是确认,可以先登录 htt ...

  7. ShareDrop – 苹果 AirDrop 服务的 HTML5 实现

    ShareDrop 是苹果 AirDrop 服务的 HTML5 版本,你可以直接在设备之间传输文件,而无需先上传到任何服务器.它使用 WebRTC 来实现安全的点对点文件传输.目前 ShareDrop ...

  8. 定时器相关 setTimeout setInterval 函数节流

    这个问题也是在参加百度的前端技术学院中遇到的 任务中需要用js实现动画  导师给的评价中setInterval会导致bug 当时不理解   下面把自己学习的过程分享出来 再次理解单线程   老是说js ...

  9. JS 事件代理

    事件处理器:onclick.onmouseover.... 在传统的事件处理中,你需要为每一个元素添加或者是删除事件处理器.然而,事件处理器将有可能导致内存泄露或者是性能下降——你用得越多这种风险就越 ...

  10. iOS中的物理引擎

    目前知名的2D物理引擎有 Box2d,和Chipmunk,这些是跨平台的.但苹果本身也封装了一个物理引擎, UIDynamic是从iOS 7开始引入的一种新技术,隶属于UIKit框架.这可以让开发人员 ...