High force SQL writing: line to line comparison

Posted by vcv on Mon, 07 Mar 2022 03:09:41 +0100

Environmental preparation

Database version: MySQL 5.7.20-log

Create table SQL

DROP TABLE IF EXISTS `t_ware_sale_statistics`;
CREATE TABLE `t_ware_sale_statistics` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Primary key id',
  `business_id` bigint(20) NOT NULL COMMENT 'Business organization code',
  `ware_inside_code` bigint(20) NOT NULL COMMENT 'Commodity self coding',
  `weight_sale_cnt_day` double(16,4) DEFAULT NULL COMMENT 'Average daily sales',
  `last_thirty_days_sales` double(16,4) DEFAULT NULL COMMENT 'Sales volume in the last 30 days',
  `last_sixty_days_sales` double(16,4) DEFAULT NULL COMMENT 'Sales volume in the last 60 days',
  `last_ninety_days_sales` double(16,4) DEFAULT NULL COMMENT 'Sales volume in the last 90 days',
  `same_period_sale_qty_thirty` double(16,4) DEFAULT NULL COMMENT '30 day sales in the same period last year',
  `same_period_sale_qty_sixty` double(16,4) DEFAULT NULL COMMENT '60 day sales in the same period last year',
  `same_period_sale_qty_ninety` double(16,4) DEFAULT NULL COMMENT '90 day sales in the same period last year',
  `create_user` bigint(20) DEFAULT NULL COMMENT 'Founder',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Creation time',
  `modify_user` bigint(20) DEFAULT NULL COMMENT 'Final modifier',
  `modify_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Final modification time',
  `is_delete` tinyint(2) DEFAULT '2' COMMENT 'Delete, 1: Yes, 2: no',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_business_ware` (`business_id`,`ware_inside_code`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='Commodity sales statistics';

Initialization data

769063 pieces of data were prepared

Demand background

When selling goods under a business organization, the same business organization can sell different goods, and the same goods can be sold in different business organizations, that is to say, the relationship between business organization and goods is many to many

Suppose there are n organizations and there are several commodities under each organization. How can we query the sales of their commodities under these stores?

The specific points are similar as follows

How to find out the sales of goods 1000, 1001, 1003, 1002, 1003, 1004 and 1006, 1008 and 1009 under 100001 and 100003

It is equivalent to the query of double-layer list (set of commodity list in business organization list); Business organization list and commodity list are not fixed, but dynamic

Then the question is: how to query the sales of some goods under multiple business organizations

As soon as I describe the problem, it may be more vague. Just understand the meaning!

Circular query

It is easy to think of this. At the code level, the list of business institutions is circulated. Each business institution checks the database once. The pseudo code is as follows:

The specific SQL is similar to the following

SQL can walk index

The implementation is simple and easy to understand. SQL can also go through the index. Everything seems to be perfect

However, the reality is: the department development specification constraints, can not cycle to check the database

Oh, I can only give up this way and find another way

OR splicing

Through the dynamic SQL function of MyBatis, SQL splicing is carried out, similar to the following

The specific SQL is similar to the following

SQL can also be indexed

The implementation is simple and easy to understand. SQL can also index and query the database only once. It seems feasible

The only pity is that it costs a little OR. If there are more business institutions, the SQL will be longer

As one of the candidates, let's move on

Mixed query filtering

It also uses Mybatis's dynamic SQL to create a business_id , list together, ware_inside_code together, similar to the following

The specific SQL is similar to the following

SQL can also be indexed

The implementation is simple and easy to understand. SQL can also index and query the database only once. It seems feasible

But: the result set found is greater than or equal to the result set we want. You are good, you are good!

Therefore, we also need to filter the found result set to filter out the result set we want

As one of the candidates, let's move on

Line to line comparison

The function of row to row comparison is added IN SQL-92. IN this way, the parameters of the comparison predicates =, <, > and IN predicates are not only scalar values, but also value lists

Of course, you still need to use Mybatis's dynamic SQL, similar to the following

The specific SQL is similar to the following

SQL can also be indexed

The implementation is simple. SQL can also go through the index, and only query the database once. It feels feasible

It's just: it's a little hard to understand, because we usually use so little, so this way of writing looks strange

In addition, row to row comparison is the SQL specification, not the specification of a relational database. That is to say, all relational databases should support this writing method

summary

1. Finally, the method of line to line comparison is selected to realize the requirements

Don't ask me why, asking is forcing Ge Gao!

2. There are often many ways to realize a requirement. We need to consider the business and various constraints and choose the most appropriate one

3. Row to row comparison was introduced into SQL-92, which was formulated in 1992

Line to line comparison is not a new feature, but a basic function that has existed for a long time!

reference resources

  • Advanced SQL tutorial
  • Magic SQL MySQL execution plan → EXPLAIN, let's understand the execution process of SQL!
  • Magic SQL performance optimization → let SQL fly
  • The magic SQL passed by → did you really use the index

Topics: Java MySQL