(内部)加入该表时,是什么导致此内存泄漏的?

时间:2018-10-08 08:19:13

标签: php mysql

我脑中有一条SQL,它将并且应该在1秒内运行:

SELECT mem.`epid`,
       mem.`model_id`,
       em.`UKM_Make`,
       em.`UKM_Model`,
       em.`UKM_CCM`,
       em.`UKM_Submodel`,
       em.`Year`,
       em.`UKM_StreetName`,
       f.`fit_part_number`
FROM `table_one` AS mem
INNER JOIN `table_two` em ON mem.`epid` = em.`ePID`
INNER JOIN `table_three` f ON `mem`.`model_id` = f.`fit_model_id`
LIMIT 1;

当我在终端中运行时,此SQL将在16秒内执行。但是,如果我删除该行:

INNER JOIN `table_three` f ON `mem`.`model_id` = f.`fit_model_id`

然后它会在0.03秒内执行。不幸的是,我不确定如何调试MYSQL性能问题。这导致我的PHP脚本用尽了内存,无法执行查询。

这是我的表结构:

  

table_one

+----------+---------+------+-----+---------+-------+
| Field    | Type    | Null | Key | Default | Extra |
+----------+---------+------+-----+---------+-------+
| epid     | int(11) | YES  |     | NULL    |       |
| model_id | int(11) | YES  |     | NULL    |       |
+----------+---------+------+-----+---------+-------+
  

table_two

+----------------+--------------+------+-----+---------+-------+
| Field          | Type         | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+-------+
| id             | int(11)      | NO   | PRI | NULL    |       |
| ePID           | int(11)      | NO   |     | NULL    |       |
| UKM_Make       | varchar(100) | NO   |     | NULL    |       |
| UKM_Model      | varchar(100) | NO   |     | NULL    |       |
| UKM_CCM        | int(11)      | NO   |     | NULL    |       |
| UKM_Submodel   | varchar(100) | NO   |     | NULL    |       |
| Year           | int(11)      | NO   |     | NULL    |       |
| UKM_StreetName | varchar(100) | NO   |     | NULL    |       |
| Vehicle Type   | varchar(100) | NO   |     | NULL    |       |
+----------------+--------------+------+-----+---------+-------+
  

table_three

+-----------------+-------------+------+-----+---------+----------------+
| Field           | Type        | Null | Key | Default | Extra          |
+-----------------+-------------+------+-----+---------+----------------+
| fit_fitment_id  | int(11)     | NO   | PRI | NULL    | auto_increment |
| fit_part_number | varchar(50) | NO   |     | NULL    |                |
| fit_model_id    | int(11)     | YES  |     | NULL    |                |
| fit_year_start  | varchar(4)  | YES  |     | NULL    |                |
| fit_year_end    | varchar(4)  | YES  |     | NULL    |                |
+-----------------+-------------+------+-----+---------+----------------+

以上内容是从describe $table_name

输出的

我明显缺少什么吗?如果没有,我该如何找出包含table_three的原因导致如此缓慢的响应时间?

编辑一个:

建立索引建议(使用CREATE INDEX fit_model ON table_three (fit_model_id)后,它将在0.00秒内执行查询(在MYSQL中)。删除限制后,仍在执行建议后仍在运行...所以还不够。Anton关于使用EXPLAIN我用它并得到以下输出:

+------+-------------+-------+------+---------------+-----------+---------+----------------------+-------+-------------------------------------------------+
| id   | select_type | table | type | possible_keys | key       | key_len | ref                  | rows  | Extra                                           |
+------+-------------+-------+------+---------------+-----------+---------+----------------------+-------+-------------------------------------------------+
|    1 | SIMPLE      | mem   | ALL  | NULL          | NULL      | NULL    | NULL                 |  5587 | Using where                                     |
|    1 | SIMPLE      | f     | ref  | fit_model     | fit_model | 5       | mastern.mem.model_id |    14 |                                                 |
|    1 | SIMPLE      | em    | ALL  | NULL          | NULL      | NULL    | NULL                 | 36773 | Using where; Using join buffer (flat, BNL join) |
+------+-------------+-------+------+---------------+-----------+---------+----------------------+-------+-------------------------------------------------+

编辑两次

我使用以下查询根据建议添加了外键:

ALTER TABLE `table_one`
ADD CONSTRAINT `model_id_fk_tbl_three`
FOREIGN KEY (`model_id`)
REFERENCES `table_three` (`fit_model_id`)

MYSQL仍在执行命令-行很多,因此请半途而废。借助PHP,我可以像这样分解查询并构建数组,因此我想这可能解决了这个问题-想做更多的事情来尝试减少执行时间吗?

2 个答案:

答案 0 :(得分:3)

基于每个人的评论等。我设法执行了一些操作,这些操作使我的查询运行得更快,并且不会崩溃我的脚本。

1)索引

我在table_three上为字段fit_model_id创建了一个索引:

CREATE INDEX fit_model ON `table_three` (`fit_model_id`);

这使我的LIMIT 1查询的执行时间从16秒变为0.03秒(在MYSQL CLI中)。

但是,大约100行仍然比我想象的要花费更长的时间。

2)外键

我创建了一个使用以下查询链接table_onemodel_id = table_threefit_model_id的外键:

ALTER TABLE `table_one`
ADD CONSTRAINT `model_id_fk_tbl_three`
FOREIGN KEY (`model_id`)
REFERENCES `table_three` (`fit_model_id`)

这肯定有帮助,但仍然觉得可以做更多的事情。

3)优化表

然后我在这些表上使用了OPTIMIZE TABLE

  • table_one
  • table_three

然后,这使我的脚本可以正常工作,并且查询比以往任何时候都快。但是,我遇到的问题是一个大数据集,所以我让查询在MYSQL CLI中运行,同时将每个脚本运行时间的LIMIT增加1000,以帮助索引过程,直到开始崩溃前一直达到3万行。

CLI完成了31分8秒。所以我这样做了:

  

31 x 60 = 1860

     

1860 + 8 = 1868

     

1868/448476 = 0.0042

因此每一行需要0.0042秒才能完成-在我眼中这足够快。

感谢大家发表评论并帮助我调试和解决问题:)

答案 1 :(得分:2)

基于评论的正确答案如下:

  1. 如果长执行select语句,则在SELECT之前添加EXPLAIN语句
  2. 检查特定表的子查询中的possible_keys是否为空。
  3. 为在步骤2中找到的表添加FOREIGN KEY。如果表很大,建议调整MAX_EXECUTION_TIME变量(可以对单个查询完成)
  4. 对于大量的插入/更新/删除操作,OPTIMIZE TABLE也可以调整性能。