我有一个架构
applicants - id, max_res_id, max_visa_id
applicant_files - id, applicatid, fileid, filetype
files - id, name, filetype
申请人 -
CREATE TABLE `applicants` (
`id` char(36) NOT NULL,
`max_res_id` char(36) NOT NULL,
`max_visa_id` char(36) NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_res_id` (`max_res_id`) USING BTREE,
KEY `idx_visa_id` (`max_visa_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
applicant_files
CREATE TABLE `applicant_files` (
`id` char(36) CHARACTER SET latin1 NOT NULL,
`applicantid` char(36) CHARACTER SET latin1 DEFAULT NULL,
`fileid` char(36) CHARACTER SET latin1 DEFAULT NULL,
`filetype` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `q_applicantfile_fileid` (`fileid`),
KEY `u_applicantfile_applid` (`applicantid`),
KEY `idx_filetype` (`filetype`) USING BTREE,
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
文件
CREATE TABLE `files` (
`id` char(36) NOT NULL,
`filetype` tinyint(1) NOT NULL,
`name` text,
PRIMARY KEY (`id`),
KEY `idx_filetype` (`filetype`) USING BTREE,
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
max_res_id, max_visa_id
引用" id" applicant_files
的
fileid
指的是" id" files
现在我有两个不同的查询 -
select f.id as resumeId, f.name as resumeName, f.date_entered as resumeDate,
a.id as applId
from oepl_applicants a
inner join applicant_files af
ON ( a.id in ('id1', 'id2')
and a.id = af.applicantid
and a.max_res_id = af.id
and af.filetype = 1
and a.max_res_id != ''
and a.max_res_id is not null )
inner join files f
ON ( af.fileid = f.id
and f.filetype = 1 )
select f.id as visaId, f.name as visaName, f.date_entered as visaDate,
a.id as applId
from oepl_applicants a
inner join applicant_files af
ON ( a.id in ('id1', 'id2')
and a.id = af.applicantid
and a.max_visa_id = af.id
and af.filetype = 2
and a.max_visa_id != ''
and a.max_visa_id is not null )
inner join files f
ON ( af.fileid = f.id
and f.filetype = 2 )
对于200个ID(id1,id2,... id200),第一个查询在2秒内返回结果,而第二个查询在30秒内返回结果。
这里可能出现什么问题?
这两个查询的唯一区别是文件类型不同,并且连接在2个不同的列上。 PS - 与max_res_id中的值相比,max_visa_id中的很多值都为null(空)
答案 0 :(得分:1)
感谢您CREATE TABLEs
。
加入latin1
vs utf8
无效使用索引!
虽然在这种情况下无关紧要,但请将“过滤”子句移到WHERE
子句中,并在ON
子句中仅保留描述表如何相关的子句。例如,在第一个查询中:
inner join applicant_files af
ON a.id = af.applicantid
and a.max_res_id = af.id
inner join files f ON af.fileid = f.id
WHERE a.id in ('id1', 'id2')
and f.filetype = 1
and af.filetype = 1
and a.max_res_id != ''
and a.max_res_id is not null
优化程序将决定查看表格的顺序。从“过滤”条款中,它希望看到这些:
a: INDEX(max_res_id, id)
af and f: INDEX(filetype) -- but see note below
然后优化器会看到是否很容易进入“下一个”表。这些可能是有益的。 (我注意到你已经有(id)
。)
af: INDEX(applicantid, filetype) -- in either order
请运行EXPLAIN SELECT
以查看优化程序选择的顺序,以及它为每个后续表格选择的索引。
char(36)
闻起来像UUID或GUID。你做出CHARACTER SET latin1
而不是utf8
是件好事。但由于随机性,这些字段对索引很糟糕。见my blog。如果可能,请切换到MEDIUMINT UNSIGNED AUTO_INCREMENT
,尽管它会涉及大量代码和架构更改。
filetype
的两个实例是多余的?也就是说,您是否需要检查两个表的文件类型?这是一项额外的工作。
为了帮助初始查询,我们需要理解filetype
的值的分布。 1
比2
更常见(或更少)吗? 1
(或2
)的行是否会在表格的开头(或结尾)附近聚集?
桌子有多大?如果innodb_buffer_pool_size
有什么价值?你有多少RAM?
以下部分或全部可能密谋让您表现不佳:
如果这些评论未能提供足够的速度,我建议重新构建查询以延迟从f
获取:
SELECT f..., x...
FROM (
SELECT ... FROM applicants AS a
JOIN applicant_files AS af ON ...
WHERE ...
) AS x
JOIN files AS f ON x.fileid = f.id
WHERE f.filetype = 1
警告:“此处显示的架构是缩小版本。” - 由于您的缩小,我推荐的可能不够!