【问题标题】:MySQL Performance Degrades during Concurrent Stored Proc Execution并发存储过程执行期间 MySQL 性能下降
【发布时间】:2017-12-06 16:42:05
【问题描述】:

机器规格:macOS Sierra,版本 10.12.5,内存 8 GB

MySQL 版本: MySQL Enterprise Server - 高级版(商业版)3 innodb_version : 5.7.18

问题:当不同会话同时调用同一个存储过程时,响应时间会延迟很多。

下面的 SQL 是每次执行需要 0.12 秒的 SQL。为了模拟这个问题,我在 while 循环中运行以下 SQL,该循环迭代 30 次,因此每次执行存储过程平均需要 3 秒。

但是,当我从不同的终端/会话同时运行相同的存储过程时,两个存储过程都需要将近 50 秒

表在 innodb 中创建,缓冲区大小和读/写 io 设置为正常值。

查询

 SELECT MIN(BEGIN_date) , MAX(END_date) 
   FROM employee e, department d 
  WHERE e.employee_ID = d.employee_ID 
    AND d.Department_ID = 72641 ;

解释扩展计划如下(完美使用索引)

----+-------------+-------+------------+------+------------------+----------    --------+---------+-------------------------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys    | key               | key_len | ref                           | rows | filtered | Extra       |
+----+-------------+-------+------------+------+------------------+------------------+---------+-------------------------------+------+----------+-------------+
|  1 | SIMPLE      | d     | NULL       | ref  | deptmnt_dept_idx | deptmnt_dept_idx | 4       | const                         |  808 |   100.00 | NULL        |
|  1 | SIMPLE      | e     | NULL       | ref  | Emp_Name_Dt _idx | Emp_Name_Dt _idx | 4       | radar_bridge_db.d.Employee_ID |  156 |   100.00 | Using index |
+----+-------------+-------+------------+------+------------------+------------------+---------+-------------------------------+------+----------+-------------+

存储过程:

CREATE PROCEDURE `fetchEmployeeDetails`()
BEGIN

DECLARE l_StartDate DATE DEFAULT CURRENT_DATE()-INTERVAL 7 DAY;
DECLARE l_EndDate DATE DEFAULT CURRENT_DATE();

DECLARE I_Range INT DEFAULT 0;

WHILE I_Range < 30 DO   

    SELECT MIN(BEGIN_date) , MAX(END_date)  
      INTO l_StartDate,  l_EndDate  FROM employee e, department d 
     WHERE e.employee_ID = d.employee_ID AND d.Department_ID = 72641 ;

    SET I_Range = I_Range + 1;

 END WHILE;

END;

当从不同的终端/会话同时调用同一个 SP 时,两个 SP 都需要将近 50 秒。

该示例在同一台 Mac 机器上的 MySQL 社区版和企业版(开启线程池)上运行,但问题仍然存在。 如果您有任何解决此性能问题的方法,请告诉我。

CREATE TABLE `employee` (
  `COMPANY_ID` int(11) NOT NULL,
  `COMPANY_NAME` varchar(255) CHARACTER SET utf8 NOT NULL,
  `EMPLOYEE_ID` int(11) NOT NULL,
  `BEGIN_DATE` timestamp NULL DEFAULT NULL,
  `END_DATE` timestamp NULL DEFAULT NULL,
  KEY `Emp_Name_Dt_idx` (`EMPLOYEE_ID`,`BEGIN_DATE`,`END_DATE`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

CREATE TABLE `department` (
  `Employee_ID` int(11) NOT NULL,
  `Department_ID` int(11) NOT NULL,
  KEY `deptmnt_dept_idx` (`Department_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

【问题讨论】:

  • 提供SHOW CREATE TABLE和/或限定所有列,以便我们知道END_date在哪个表中!没有这个,我们无法给你答案!
  • 为什么循环运行 30 次?似乎每次都给出相同的结果!
  • 感谢 Rick 对此进行调查。我正在运行 30 次,以便让我有一个窗口期(即 3 秒)来获得另一个并发执行运行。还按要求将创建表 DDL 添加到问题中。
  • 另请注意,某些存储过程的并发执行确实挂起,即使它们在单独执行时工作正常(
  • 您是否尝试过在其他操作系统(Mac 除外)中进行性能比较?

标签: mysql performance stored-procedures explain


【解决方案1】:

请重新考虑架构。

名为employee 的表应该谈论一个人。如果该人多次受雇,您所拥有的似乎有多行。也许它应该被称为tenure,并与employee分开。

department 应该是一个部门。您所拥有的是员工和部门之间的多:多映射。但是,一个员工可以属于多个部门吗?如果不是,那么它是一个 1:many 映射,并且不需要该表。而是在employee 表中添加department_id

而且,您需要在每张桌子上使用PRIMARY KEY

PRIMARY KEY(employee_id) -- on employee
PRIMARY KEY(employee_id, start_date, end_date) -- on tenure
PRIMARY KEY(department_id) -- on department
PRIMARY KEY(department_id, employee_id) -- on many:many mapping
INDEX(department_id) -- on employee, if 1:many
INDEX(employee_id, department_id) -- if many:many

More discussion on many:many 。

在所有这些之后,我们可以继续讨论你的计时异常,如果它仍然存在的话。

【讨论】:

  • 嗨 Rick,正如我所提到的,员工和部门表的构建是为了复制和共享有问题的场景。如果有意义的话,我们可以将表的名称从“员工”更改为“工资”。员工(工资)-部门关系可能不是规范化的,但我们遇到的问题是仅在存储过程的并发执行期间才会出现。这不仅适用于这种情况,也适用于其他情况。
猜你喜欢
  • 2018-02-23
  • 1970-01-01
  • 2012-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-28
  • 1970-01-01
  • 2021-09-19
相关资源
最近更新 更多