简体   繁体   English

如何加快 MySQL 中超过 2 个表的查询

[英]How to speed up query in MySQL over 2 tables

I running a very simple query that takes more than 60 seconds.我运行了一个非常简单的查询,耗时超过 60 秒。 Is there a way to speed up the query?有没有办法加快查询速度?

SELECT
    AVG(salary.salary_amount),
    invoice.invoiced_date
FROM sample_staff.salary

INNER JOIN sample_staff.invoice ON 1=1
   AND salary.employee_id = invoice.employee_id
   AND invoice.invoiced_date BETWEEN salary.from_date AND salary.to_date
;

Each individual query runs OK:每个单独的查询运行正常:

SELECT
    COUNT(salary.salary_amount) 
FROM sample_staff.salary
; -- 2,844,047 records in 2.25 seconds

SELECT
    COUNT(invoice.invoiced_date) 
FROM sample_staff.invoice
; -- 973,488 records in 1.156 seconds

The structures of the table are:表的结构如下:

CREATE TABLE `salary` (
   id` int unsigned NOT NULL AUTO_INCREMENT,
   employee_id` int unsigned NOT NULL DEFAULT '0',
  `salary_amount` decimal(11,2) NOT NULL DEFAULT '0.00',
  `from_date` date DEFAULT NULL,
  `to_date` date DEFAULT NULL,
  `insert_dt` datetime NOT NULL,
  `insert_user_id` int NOT NULL DEFAULT '-1',
  `insert_process_code` varchar(255) DEFAULT NULL,
  `update_dt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `update_user_id` int NOT NULL DEFAULT '-1',
  `update_process_code` varchar(255) DEFAULT NULL,
  `deleted_flag` tinyint NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `ak_salary` (`employee_id`,`from_date`,`to_date`),
  KEY `idx_employee_id` (`employee_id`),
  KEY `idx_salary_amount` (`salary_amount`),
  CONSTRAINT `salary_ibfk_1` FOREIGN KEY (`employee_id`) REFERENCES `employee` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2844050 DEFAULT CHARSET=utf8mb3

CREATE TABLE `invoice` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `employee_id` int unsigned NOT NULL,
  `invoiced_date` date NOT NULL,
  `paid_flag` tinyint NOT NULL DEFAULT '0',
  `insert_dt` datetime NOT NULL,
  `insert_user_id` int NOT NULL DEFAULT '-1',
  `insert_process_code` varchar(255) DEFAULT NULL,
  `update_dt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `update_user_id` int NOT NULL DEFAULT '-1',
  `update_process_code` varchar(255) DEFAULT NULL,
  `deleted_flag` tinyint NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`,`invoiced_date`),
  KEY `idx_employee_id` (`employee_id`)
) ENGINE=InnoDB AUTO_INCREMENT=973489 DEFAULT CHARSET=utf8mb3
/*!50100 PARTITION BY RANGE (year(`invoiced_date`))
SUBPARTITION BY HASH (month(`invoiced_date`))
SUBPARTITIONS 12
(PARTITION p1984 VALUES LESS THAN (1985) ENGINE = InnoDB,
 PARTITION p1985 VALUES LESS THAN (1986) ENGINE = InnoDB,
 PARTITION p1986 VALUES LESS THAN (1987) ENGINE = InnoDB,
 PARTITION p1987 VALUES LESS THAN (1988) ENGINE = InnoDB,
 PARTITION p1988 VALUES LESS THAN (1989) ENGINE = InnoDB,
 PARTITION p1989 VALUES LESS THAN (1990) ENGINE = InnoDB,
 PARTITION p1990 VALUES LESS THAN (1991) ENGINE = InnoDB,
 PARTITION p1991 VALUES LESS THAN (1992) ENGINE = InnoDB,
 PARTITION p1992 VALUES LESS THAN (1993) ENGINE = InnoDB,
 PARTITION p1993 VALUES LESS THAN (1994) ENGINE = InnoDB,
 PARTITION pOTHER VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */

SELECT
    salary.employee_id,
    salary.salary_amount,
    salary.from_date,
    salary.to_date
FROM sample_staff.salary
LIMIT 10;
/*
+-------------+---------------+------------+------------+
| employee_id | salary_amount |  from_date |   to_date  |
+-------------+---------------+------------+------------+
| 10001       | 60117.00      | 1986-06-26 | 1987-06-26 |
| 10001       | 62102.00      | 1987-06-26 | 1988-06-25 |
| 10001       | 66074.00      | 1988-06-25 | 1989-06-25 |
| 10001       | 66596.00      | 1989-06-25 | 1990-06-25 |
| 10001       | 66961.00      | 1990-06-25 | 1991-06-25 |
| 10001       | 71046.00      | 1991-06-25 | 1992-06-24 |
| 10001       | 74333.00      | 1992-06-24 | 1993-06-24 |
| 10001       | 75286.00      | 1993-06-24 | 1994-06-24 |
| 10001       | 75994.00      | 1994-06-24 | 1995-06-24 |
| 10001       | 76884.00      | 1995-06-24 | 1996-06-23 |
+-------------+---------------+------------+------------+
*/
SELECT
    invoice.invoiced_date,
    invoice.employee_id
FROM sample_staff.invoice
limit 10;
/*
+---------------+-------------+
| invoiced_date | employee_id |
+---------------+-------------+
| 1985-12-01    | 10009       |
| 1985-12-01    | 10013       |
| 1985-12-01    | 10048       |
| 1985-12-01    | 10064       |
| 1985-12-01    | 10070       |
| 1985-12-01    | 10098       |
| 1985-12-01    | 10126       |
| 1985-12-01    | 10137       |
| 1985-12-01    | 10144       |
| 1985-12-01    | 10195       |
+---------------+-------------+

*/

I found a solution.我找到了解决方案。 Hopefully it is the right one.希望这是正确的。

I ended up adding a field to the salary table, named invoice_id, which defaults to -1 but has an invoice.id (one of them) that fulfill the conditions of the INNER JOIN我最终在工资表中添加了一个名为 invoice_id 的字段,该字段默认为 -1,但具有满足 INNER JOIN 条件的 invoice.id(其中之一)

salary.employee_id = invoice.employee_id
AND invoice.invoiced_date BETWEEN salary.from_date AND salary.to_date

so now the INNER JOIN is所以现在 INNER JOIN 是

INNER JOIN sample_staff.invoice ON 1=1
    AND invoice.id = salary.invoice_id

and added a WHERE clause at the end of the query并在查询末尾添加了 WHERE 子句

WHERE 1=1
    AND salary.invoice_id > 0

Now the query finished in 58 seconds, whereas previously it did not finished in 60 seconds (Workbench aborted after 60 seonds)现在查询在 58 秒内完成,而之前它没有在 60 秒内完成(工作台在 60 秒后中止)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM