【发布时间】:2019-06-11 22:42:01
【问题描述】:
我用 PHP 编写了一个带有 MySQL 数据库的工作请求系统,但我遇到了查询速度慢的问题。
我的架构(简化)如下:
tbl_job
工作编号
job_desc
requester_user_id
tbl_user
用户ID
用户名
tbl_workermap
workermap_id
工作编号
worker_user_id
一个包含作业的表、一个用于可能工作人员的用户表和一个用于将工作人员映射到工作的表。一个工作可以有一个或多个工人,一个工人可以有一个或多个工作。
tbl_user 包含请求工作的用户和从事工作的用户,因此用户 ID 存储在 tbl_workermap 中的 worker_user_id 和 tbl_job 中的 requester_user_id 下
当一个作业被记录时,它会在 tbl_job 中创建一个条目,但在 tbl_workermap 中没有任何内容,直到有人专门分配了一个工人。这意味着当我查询作业时,我会使用左连接来执行此操作,因为 tbl_workermap 中没有每个作业的条目:
SELECT
job.job_id,
job.job_desc,
workermap.worker_user_id,
worker.worker_name
FROM tbl_job AS job
LEFT JOIN tbl_workermap AS workermap
ON job.job_id = workermap.job_id
LEFT JOIN tbl_user AS worker
ON workermap.worker_user_id = worker.user_id
系统已经使用了一段时间,现在我在 tbl_job 中有大约 8000 个条目,在 tbl_workermap 中有 7000 个条目,检索所有结果需要 4 秒以上。 EXPLAIN 查询显示 tbl_workermap 连接返回大约 7000 行和“使用 where;使用连接缓冲区(块嵌套循环)”。
有什么办法可以加快速度吗?
编辑:添加表格信息
我简化了一些事情来解释,但这是实际的表结构。还有更多连接,但 tbl_workermap 是唯一有问题的连接:
CREATE TABLE `tbl_job` (
`job_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`job_title` varchar(100) DEFAULT NULL,
`job_description` text,
`job_added_datetime` int(11) DEFAULT '0',
`job_due_datetime` int(11) NOT NULL DEFAULT '0',
`job_time_estimate` int(11) DEFAULT NULL,
`job_additional_fields` text,
`addedby_user_id` int(11) NOT NULL DEFAULT '0',
`requester_user_id` int(11) NOT NULL DEFAULT '0',
`worker_user_id` int(11) NOT NULL DEFAULT '0',
`job_active` tinyint(4) NOT NULL DEFAULT '1',
`site_id` tinyint(4) NOT NULL DEFAULT '1',
`status_id` int(11) NOT NULL DEFAULT '1',
`estimategroup_id` int(11) DEFAULT '1',
`brand_id` int(11) DEFAULT '1',
`job_isproject` tinyint(4) DEFAULT NULL,
PRIMARY KEY (`job_id`),
FULLTEXT KEY `job_title` (`job_title`,`job_description`,`job_additional_fields`)
) ENGINE=MyISAM AUTO_INCREMENT=8285 DEFAULT CHARSET=latin1
CREATE TABLE `tbl_user` (
`user_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_shortname` varchar(30) DEFAULT NULL,
`user_name` varchar(30) DEFAULT NULL,
`user_password` varchar(50) DEFAULT NULL,
`user_password_reset_uuid` varchar(50) DEFAULT NULL,
`user_email` varchar(50) DEFAULT NULL,
`user_description` text,
`user_sortorder` int(11) NOT NULL DEFAULT '0',
`user_isworker` tinyint(4) NOT NULL DEFAULT '0',
`user_active` tinyint(4) NOT NULL DEFAULT '1',
`site_id` tinyint(4) NOT NULL DEFAULT '0',
`user_avatar_file_id` int(11) DEFAULT NULL,
`user_avatar_hub_url` varchar(100) DEFAULT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=MyISAM AUTO_INCREMENT=917 DEFAULT CHARSET=latin1
CREATE TABLE `tbl_workermap` (
`workermap_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`job_id` int(11) DEFAULT NULL,
`workermap_datetime_added` int(11) DEFAULT NULL,
`workermap_datetime_removed` int(11) DEFAULT NULL,
`worker_user_id` int(11) DEFAULT NULL,
`addedby_user_id` int(11) DEFAULT NULL,
`removedby_user_id` int(11) DEFAULT NULL,
`site_id` int(11) DEFAULT NULL,
`workermap_isassigned` int(11) DEFAULT NULL,
`workermap_active` int(11) NOT NULL DEFAULT '1',
PRIMARY KEY (`workermap_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7145 DEFAULT CHARSET=latin1
显示索引
+---------+---+-----------+---+-----------------------+------+------+------+------+-----+----------+--+--+
| tbl_job | 0 | PRIMARY | 1 | job_id | A | 8283 | NULL | NULL | | BTREE | | |
+---------+---+-----------+---+-----------------------+------+------+------+------+-----+----------+--+--+
| tbl_job | 1 | job_title | 1 | job_title | NULL | 1 | NULL | NULL | YES | FULLTEXT | | |
| tbl_job | 1 | job_title | 2 | job_description | NULL | 1 | NULL | NULL | YES | FULLTEXT | | |
| tbl_job | 1 | job_title | 3 | job_additional_fields | NULL | 1 | NULL | NULL | YES | FULLTEXT | | |
+---------+---+-----------+---+-----------------------+------+------+------+------+-----+----------+--+--+
+----------+---+---------+---+---------+---+-----+------+------+--+-------+--+--+
| tbl_user | 0 | PRIMARY | 1 | user_id | A | 910 | NULL | NULL | | BTREE | | |
+----------+---+---------+---+---------+---+-----+------+------+--+-------+--+--+
+---------------+---+---------+---+--------------+---+------+------+------+--+-------+--+--+
| tbl_workermap | 0 | PRIMARY | 1 | workermap_id | A | 7184 | NULL | NULL | | BTREE | | |
+---------------+---+---------+---+--------------+---+------+------+------+--+-------+--+--+
解释查询
+---+--------+----------------+--------+---------+---------+------+-------------------------------+------+----------------------------------------------------+
| 1 | SIMPLE | job | ALL | NULL | NULL | NULL | NULL | 8283 | Using where; Using temporary; Using filesort |
+---+--------+----------------+--------+---------+---------+------+-------------------------------+------+----------------------------------------------------+
| 1 | SIMPLE | estimategroup | eq_ref | PRIMARY | PRIMARY | 4 | jobq.job.estimategroup_id | 1 | Using where |
| 1 | SIMPLE | brand | eq_ref | PRIMARY | PRIMARY | 4 | jobq.job.brand_id | 1 | Using index condition |
| 1 | SIMPLE | site | eq_ref | PRIMARY | PRIMARY | 4 | jobq.job.site_id | 1 | Using where |
| 1 | SIMPLE | addedby | eq_ref | PRIMARY | PRIMARY | 4 | jobq.job.addedby_user_id | 1 | Using index condition |
| 1 | SIMPLE | requester | eq_ref | PRIMARY | PRIMARY | 4 | jobq.job.requester_user_id | 1 | Using index condition |
| 1 | SIMPLE | worker | eq_ref | PRIMARY | PRIMARY | 4 | jobq.job.worker_user_id | 1 | Using index condition |
| 1 | SIMPLE | status | ALL | PRIMARY | NULL | NULL | NULL | 6 | Using where; Using join buffer (Block Nested Loop) |
| 1 | SIMPLE | workermap | ALL | NULL | NULL | NULL | NULL | 7184 | Using where; Using join buffer (Block Nested Loop) |
| 1 | SIMPLE | user_workermap | eq_ref | PRIMARY | PRIMARY | 4 | jobq.workermap.worker_user_id | 1 | Using where |
| 1 | SIMPLE | categorymap | ALL | NULL | NULL | NULL | NULL | 1 | Using where; Using join buffer (Block Nested Loop) |
| 1 | SIMPLE | category | eq_ref | PRIMARY | PRIMARY | 4 | jobq.categorymap.category_id | 1 | Using where |
+---+--------+----------------+--------+---------+---------+------+-------------------------------+------+----------------------------------------------------+
【问题讨论】:
-
请发布 SHOW CREATE TABLE tbl_job 的 TEXT 结果;和 tbl_worker;和 tbl_workermap;以及 SHOW INDEX FROM tbl_job;和 tbl_worker;和 tbl_workermap;进行分析。另外,请发布 EXPLAIN .... 结果。
-
@WilsonHauck 我已经添加了该信息,谢谢。
-
目前,您需要两个索引来涵盖 JOIN 的左右对象的基本规则 = 需要一个索引。 1. ALTER TABLE tbl_workermap ADD INDEX idx_t_w_map_job_id (job_id) 2. ALTER TABLE tbl_workermap ADD INDEX idx_t_w_map_wrk_user_id (worker_user_id) 创建后运行EXPLAIN .....查看新的执行计划
-
@WilsonHauck 谢谢,我已经添加了这两个索引,这就成功了,现在几乎是即时的。如果您可以将该信息添加为答案,我可以将其标记为已接受,以便您获得信用。
-
@WilsonHauck 我很乐意这样做,并且刚刚这样做了 :) 再次感谢。
标签: mysql join query-optimization