我的MySQL查询很慢。我有3个表:工作(200k记录),位置(300k),职位(700k)。
SELECT
j.job_offerid
FROM `job_offer` AS j
INNER JOIN `job_offer_localitymap` AS d ON d.`job_offerid` = j.`job_offerid` AND
`gps_localityid` IN(35, 3301, 3302, 3303, 3305, 3306, 3307, 3308, 124, 3811, 3805, 3709, 3808, 3809)
WHERE
j.`status` = 1 AND
j.`job_offerid` IN(
SELECT `job_offerid`
FROM `job_offer_positionmap`
WHERE `cb_job_positionid` IN (1001, 6, 629, 7, 8, 9, 10, 11, 12, 13, 1, 15, 16, 17))
ORDER BY j.`job_offerid` DESC
LIMIT 3
我必须过滤位置和地点,所以我使用了IN。
EXPLAIN:使用where;使用索引;使用临时;使用filesort;开始临时
仅使用行的表格方案:
CREATE TABLE `job_offer` (
`job_offerid` int(13) NOT NULL AUTO_INCREMENT,
`status` int(13) NOT NULL DEFAULT '1',
PRIMARY KEY (`job_offerid`),
KEY `status` (`status`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `job_offer_localitymap` (
`job_offer_localitymapid` int(13) NOT NULL AUTO_INCREMENT,
`gps_localityid` int(13) NOT NULL,
`job_offerid` int(13) NOT NULL,
PRIMARY KEY (`job_offer_localitymapid`),
KEY `gps_localityid` (`gps_localityid`),
KEY `job_offerid` (`job_offerid`),
KEY `gps_localityid_job_offerid` (`gps_localityid`,`job_offerid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;
CREATE TABLE `job_offer_positionmap` (
`job_offer_positionmapid` int(13) NOT NULL AUTO_INCREMENT,
`cb_job_positionid` int(13) NOT NULL,
`job_offerid` int(13) NOT NULL,
PRIMARY KEY (`job_offer_positionmapid`),
KEY `cb_job_positionid` (`cb_job_positionid`),
KEY `job_offerid` (`job_offerid`),
KEY `cb_job_positionid_job_offerid` (`cb_job_positionid`,`job_offerid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;
索引无处不在。
感谢您的任何建议
答案 0 :(得分:1)
您的加入将受益于复合
job_offer_localitymap.(job_offerid,gps_localityid)
也就是说,与该表中现有的复合材料相反。
因此你可以放弃这两个:
KEY `gps_localityid` (`gps_localityid`),
KEY `job_offerid` (`job_offerid`),
因为你会留下两个复合索引,其中左边大部分被其他查询使用,这两个查询受益于上面两个我刚才说要放弃
在您的查询第5行中,保持一致并使用别名j
,因为我必须寻找(不长)以查看哪个表
在我看来,job_offer中的KEY status
(status
)可能相对无用但我不了解其他查询。但是,当您的数据类型很薄时,job_offer(job_offerid,status)上的复合可能会使您的许多查询飞起来,因为covering index
不需要追踪数据页。
对于job_offer_positionmap
,这可能是一个连接,删除慢速子查询和开发人员选择,以便在那里添加复合。从概念上讲,连接类似于第一个连接。
我认为in子句一般没有问题,因为mysql CBO基于成本的优化器应该处理它。
但这些只是建议,因为添加索引并非完全没有缺点。这是一个脆弱的平衡行为,但最终你可能会发现这个查询不仅会飞,而且还会发生其他问题。
答案 1 :(得分:0)
您正在使用join
进行过滤。所以我会把这个逻辑移到where
子句:
SELECT j.job_offerid
FROM `job_offer`
WHERE j.`status` = 1 AND
j.`job_offerid` IN (SELECT jop.`job_offerid`
FROM `job_offer_positionmap` jop
WHERE `cb_job_positionid` IN (1001, 6, 629, 7, 8, 9, 10, 11, 12, 13, 1, 15, 16, 17)
) AND
j.`job_offerid` IN (SELECT jop.`job_offerid`
FROM `job_offer_localitymap` jol
WHERE jol.gps_localityid IN (35, 3301, 3302, 3303, 3305, 3306, 3307, 3308, 124, 3811, 3805, 3709, 3808, 3809)
)
ORDER BY j.`job_offerid` DESC
LIMIT 3;
然后,对于此查询,您需要以下索引:
生成的查询应使用第一个过滤索引和order by
子句。然后它将使用其他两个索引进行过滤。