![](/img/trans.png)
[英]MySql performance degrades quickly when queries have to process a large number of rows
[英]MySQL select performance with Indexes degrades for similar queries
我有一个模式
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
referes到的“ID” applicant_files
fileid
指的是“ID” files
现在我有2个不同的查询-
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中的许多值都为空(空)
谢谢您的CREATE TABLEs
。
在latin1
vs utf8
上加入会使索引的使用无效!
尽管在这种情况下无关紧要,但是请将“ filtering”子句移至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
为CHARACTER SET latin1
而不是utf8
。 但是由于随机性,这样的字段对于索引很糟糕。 看我的博客 。 如果可能,请切换到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
警告 :“此处显示的架构是缩小版。”- 由于您的缩小, 我建议的内容可能还不够!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.