当前位置:网站首页>Explain SQL optimization in detail
Explain SQL optimization in detail
2022-07-23 17:14:00 【InfoQ】
1. Create table
CREATE TABLE `purchase_order` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT ' The primary key increases automatically id', `purchase_time` varchar(255) DEFAULT NULL COMMENT ' Purchase time ', `purchase_pre_unit_price` decimal(10,2) unsigned zerofill NOT NULL COMMENT ' Purchase reservation unit price ( element /kg)', `purchase_weight` decimal(10,2) unsigned zerofill NOT NULL COMMENT ' Incoming weight (kg)', `purchase_bill_no` varchar(255) NOT NULL COMMENT ' Purchase order No ', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=62181 DEFAULT CHARSET=utf8 COMMENT=' Purchase order ';CREATE TABLE `settlement_voucher` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT ' Self increasing ID', `purchase_bill_no` varchar(512) DEFAULT NULL COMMENT ' Purchase order No ', `settlement_bill_no` varchar(64) NOT NULL COMMENT ' Settlement doc No ', `unit_price` decimal(10,2) unsigned zerofill NOT NULL COMMENT ' Actual settlement unit price ( element /kg)', `settlement_weight` decimal(10,2) unsigned zerofill NOT NULL COMMENT ' Actual settlement weight (kg)', `cut_off_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT ' Settlement time ', PRIMARY KEY (`id`), KEY `idx_settlement_bill_no` (`settlement_bill_no`)) ENGINE=InnoDB AUTO_INCREMENT=63288 DEFAULT CHARSET=utf8 COMMENT=' Purchase statement ';CREATE TABLE `invoice` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT ' Primary key ID', `invoice_code` varchar(255) NOT NULL COMMENT ' Invoice code ', `invoice_number` varchar(255) NOT NULL COMMENT ' Invoice number ', `pay_amount` decimal(10,2) DEFAULT NULL COMMENT ' Invoice amount ', PRIMARY KEY (`id`), KEY `idx_invoice_number` (`invoice_number`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=' Invoice form ';CREATE TABLE `settlement_invoice_relation` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT ' Primary key ID', `invoice_code` varchar(255) DEFAULT NULL COMMENT ' Invoice code ', `invoice_number` varchar(255) DEFAULT NULL COMMENT ' Invoice number ', `settlement_bill_no` varchar(64) DEFAULT NULL COMMENT ' Settlement doc No ', PRIMARY KEY (`id`), KEY `idx_settlement_bill_no` (`settlement_bill_no`), KEY `idx_invoice_number` (`invoice_number`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=' invoice - Statement related table ';- Purchase order form (purchase_order) And purchase statement (settlement_voucher) Through the purchase order number (purchase_bill_no) relation . Here's what's interesting : One purchase order can correspond to multiple purchase settlement documents , adopt purchase_bill_no relation , As shown in the following data : One purchase settlement document can correspond to multiple purchase orders , adopt purchase_bill_no relation ,settlement_voucher In the table purchase_bill_no The field stores multiple purchase orders , Use English commas to separate . As shown in the following data :
- Invoice form (invoice) And statement of accounts (settlement_voucher) There is an association table (settlement_invoice_relation) Invoice table and association table use invoice_code and invoice_number Use of related settlement document table and related relationship table settlement_bill_no Related invoices and settlement documents have a many to many relationship
2. demand
- The list field has 【 Purchase time ( Multiple commas are used to separate )、 Average purchase unit price 、 Total scheduled purchase amount , Settlement doc No , Average unit price of settlement , Settlement amount , Settlement time , Invoice number ( Multiple commas are used to separate ), Invoice code ( Multiple commas are used to separate )】
- The query conditions are : Purchase time ( When one purchase settlement document corresponds to multiple purchase documents , As long as there is a purchase order within the time range , Just find out ), Settlement time , Invoice number ( When a settlement document corresponds to multiple invoices , As long as there is an invoice that can be associated , Just find out )
- Sort according to the settlement time
3. Insert data into a table
begindeclare i int; declare purchase_weight decimal(10,2);declare unit_price decimal(10,2);declare purchase_bill_no varchar(255);declare settlement_bill_no varchar(255);set i=0;while i<100000 do select ROUND(RAND()*100,2) into purchase_weight from dual; select ROUND(RAND()*10,2) into unit_price from dual; select CONCAT('purchase-',LPAD(i,8,'0')) into purchase_bill_no from dual; select CONCAT('settlement-',LPAD(i,8,'0')) into settlement_bill_no from dual; -- Insert the purchase order table , The purchase time is randomly generated insert into purchase_order(purchase_time,purchase_pre_unit_price,purchase_weight,purchase_bill_no) select (DATE_ADD(NOW(), INTERVAL FLOOR(1 - (RAND() * 864000)) SECOND )), unit_price,purchase_weight,purchase_bill_no from dual; -- Insert statement , The settlement time is randomly generated insert into settlement_voucher(purchase_bill_no,settlement_bill_no,unit_price,settlement_weight,cut_off_time) select purchase_bill_no,settlement_bill_no,unit_price,purchase_weight, (DATE_ADD(NOW(), INTERVAL FLOOR(1 - (RAND() * 864000)) SECOND )) from dual;set i=i+1; end while;endcall pre();
insert into invoice(invoice_code,invoice_number,pay_amount)VALUES('111111','1111100','1000'),('111112','1111101','1001'),('111113','1111102','1002'),('111114','1111103','1003'),('111115','1111104','1004'),('111116','1111105','1005'),('111117','1111106','1006'),('111118','1111107','1007'),('111119','1111108','1008'),('111110','1111109','1009'); INSERT into settlement_invoice_relation(invoice_code,invoice_number,settlement_bill_no)VALUES('111111','1111100','settlement-00000000'),('111112','1111101','settlement-00000000'),('111113','1111102','settlement-00000000'),('111114','1111103','settlement-00000004'),('111114','1111103','settlement-00000006'),('111114','1111103','settlement-00000030'),('111116','1111105','settlement-00000041'),('111117','1111106','settlement-00000041'),('111118','1111107','settlement-00000043');4. Start writing according to your needs SQL
4.1 The first edition
select GROUP_CONCAT(po.purchase_time) as Purchase time , AVG(IFNULL(po.purchase_pre_unit_price,0)) as Average purchase price , t.settlement_bill_no as Settlement doc No , AVG(IFNULL(t.unit_price,0)) as Average settlement price , any_value(t.cut_off_time) as Settlement time , any_value(invoice_tmp.invoice_code) as Invoice code , any_value(invoice_tmp.invoice_number) as Invoice number from settlement_voucher tleft join purchase_order po on FIND_IN_SET(po.purchase_bill_no,t.purchase_bill_no)>0left join ( select sir.settlement_bill_no, GROUP_CONCAT(i.invoice_number) invoice_number, GROUP_CONCAT(i.invoice_code) invoice_code from settlement_invoice_relation sir, invoice i where sir.invoice_code = i.invoice_code and sir.invoice_number = i.invoice_number group by sir.settlement_bill_no) invoice_tmp on invoice_tmp.settlement_bill_no = t.settlement_bill_nowhere 1=1 -- and t.settlement_bill_no='settlement-00000000'and EXISTS(select 1 from purchase_order po1 where FIND_IN_SET(po1.purchase_bill_no,t.purchase_bill_no)>0 and po1.purchase_time >='2022-07-01 00:00:00' )and EXISTS(select 1 from purchase_order po1 where FIND_IN_SET(po1.purchase_bill_no,t.purchase_bill_no)>0 and po1.purchase_time <='2022-07-23 23:59:59' )group by t.settlement_bill_no;
4.2 The second edition
CREATE TABLE `incre_table` ( `id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=' Used to split purchase settlement sheet ';-- Be careful : How many purchase orders does a purchase settlement correspond to , Here is how many pieces of data to insert in turn , I'm here 10 strip That's enough. insert into incre_table(id) VALUES(1);insert into incre_table(id) VALUES(2);insert into incre_table(id) VALUES(3);insert into incre_table(id) VALUES(4);insert into incre_table(id) VALUES(5);insert into incre_table(id) VALUES(6);insert into incre_table(id) VALUES(7);insert into incre_table(id) VALUES(8);insert into incre_table(id) VALUES(9);insert into incre_table(id) VALUES(10);select sv.cut_off_time, sv.settlement_bill_no, sv.unit_price, sv.settlement_weight, SUBSTRING_INDEX(SUBSTRING_INDEX(sv.purchase_bill_no,',',it.id),',',-1) purchase_bill_nofrom settlement_voucher svRIGHT JOIN incre_table it on it.id<=(LENGTH(sv.purchase_bill_no) - LENGTH(REPLACE(sv.purchase_bill_no,',','')) + 1)where sv.settlement_bill_no='settlement-00000000';- First of all, I created a system with only id Table of incre_table, Ten pieces of data are inserted , And these ten data must be 1-10.
- And then I use settlement_voucher Right connected incre_table, And only take incre_table in id Data less than or equal to the quantity of the purchase order . This will control this one SQL How many pieces of data should be queried ( It just happens to be the number of purchase orders corresponding to a purchase settlement ).
- And then use SUBSTRING_INDEX To split one by one settlement_voucher The purchase order number in the table

select GROUP_CONCAT(po.purchase_time) as Purchase time , AVG(IFNULL(po.purchase_pre_unit_price,0)) as Average purchase price , t.settlement_bill_no as Settlement doc No , AVG(IFNULL(t.unit_price,0)) as Average settlement price , any_value(t.cut_off_time) as Settlement time , any_value(invoice_tmp.invoice_code) as Invoice code , any_value(invoice_tmp.invoice_number) as Invoice number from ( select sv.cut_off_time, sv.settlement_bill_no, sv.unit_price, sv.settlement_weight, SUBSTRING_INDEX(SUBSTRING_INDEX(sv.purchase_bill_no,',',it.id),',',-1) purchase_bill_no from settlement_voucher sv RIGHT JOIN incre_table it on it.id<=(LENGTH(sv.purchase_bill_no) - LENGTH(REPLACE(sv.purchase_bill_no,',','')) + 1)) tleft join purchase_order po on po.purchase_bill_no = t.purchase_bill_noleft join ( select sir.settlement_bill_no, GROUP_CONCAT(i.invoice_number) invoice_number, GROUP_CONCAT(i.invoice_code) invoice_code from settlement_invoice_relation sir, invoice i where sir.invoice_code = i.invoice_code and sir.invoice_number = i.invoice_number group by sir.settlement_bill_no) invoice_tmp on invoice_tmp.settlement_bill_no = t.settlement_bill_nowhere 1=1 -- and t.settlement_bill_no='settlement-00000000'and po.purchase_time >='2022-07-01 00:00:00' and po.purchase_time <='2022-07-23 23:59:59' group by t.settlement_bill_no; Fold 
create index idx_purchase_bill_no on purchase_order(purchase_bill_no);

4.3 The third edition
select GROUP_CONCAT(po.purchase_time) as Purchase time , AVG(IFNULL(po.purchase_pre_unit_price,0)) as Average purchase price , t.settlement_bill_no as Settlement doc No , AVG(IFNULL(t.unit_price,0)) as Average settlement price , any_value(t.cut_off_time) as Settlement time , GROUP_CONCAT(DISTINCT invoice_tmp.invoice_code) as Invoice code , GROUP_CONCAT(DISTINCT invoice_tmp.invoice_number) as Invoice number from ( select sv.cut_off_time, sv.settlement_bill_no, sv.unit_price, sv.settlement_weight, SUBSTRING_INDEX(SUBSTRING_INDEX(sv.purchase_bill_no,',',it.id),',',-1) purchase_bill_no from settlement_voucher sv RIGHT JOIN incre_table it on it.id<=(LENGTH(sv.purchase_bill_no) - LENGTH(REPLACE(sv.purchase_bill_no,',','')) + 1)) tleft join purchase_order po on po.purchase_bill_no = t.purchase_bill_noleft join ( select sir.settlement_bill_no, i.invoice_number, i.invoice_code from settlement_invoice_relation sir, invoice i where sir.invoice_code = i.invoice_code and sir.invoice_number = i.invoice_number ) invoice_tmp on invoice_tmp.settlement_bill_no = t.settlement_bill_nowhere 1=1 -- and t.settlement_bill_no='settlement-00000000'and po.purchase_time >='2022-07-01 00:00:00' and po.purchase_time <='2022-07-23 23:59:59' group by t.settlement_bill_no; Fold 

边栏推荐
- PMP practice once a day | don't get lost in the exam -7.23
- MySQL:不是MySQL问题的MySQL问题
- First deep search and first wide search of graph (realized by three methods)
- pinia(菠萝)
- 串的初步认识
- 软件测试计划包括哪些内容,测试计划如何编写。分享测试计划模板
- IR Drop 、EM、Noise 和Antenna
- Keil errors and solutions (1): fcarm - output name not specified, please check 'options for target - Utilities‘
- Object.defineproperty method, data agent
- Summary of after class homework of Microcomputer Principle and technical interface
猜你喜欢
随机推荐
opencv之打开摄像头、边缘检测
[web vulnerability exploration] SQL injection vulnerability
Four cores of browser
What about the reason why GOM and GEE set up a black screen and the fact that individual equipment maps are not displayed?
Compose Canvas饼图效果绘制
PMP practice once a day | don't get lost in the exam -7.23
Object.defineProperty方法、数据代理
搜索二叉树——寻找节点,插入节点,删除节点
Pymoo学习 (3):使用多目标优化找到最优解的集合
学习MySQL这一篇就够了
Microcomputer principle and technical interface practice in class
软件测试计划包括哪些内容,测试计划如何编写。分享测试计划模板
详解一次SQL优化
July training (day 23) - dictionary tree
ROS2自学笔记:Rviz可视化工具
Ie box model and standard box model
C语言基础篇 —— 2-6 指针、数组与sizeof运算符
Lake Shore—EMPX-H2 型低温探针台
Win11如何添加图片3D效果?Win11添加图片3D效果的方法
AutoCAD基本操作









