简体   繁体   English

MySQL-加快查询速度,避免文件排序和临时

[英]MySQL - speed up query avoid filesort and temporary

my MySQL query is slow. 我的MySQL查询速度很慢。 I have 3 tables: jobs (200k records), locations (300k), positions (700k). 我有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

I must filter positions and localities so I used IN. 我必须过滤位置和地点,因此我使用了IN。

EXPLAIN: Using where; 说明:在哪里使用; Using index; 使用索引; Using temporary; 使用临时; Using filesort; 使用文件排序; Start temporary 临时开始

Table scheme with only used rows: 仅使用行的表方案:

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;

Indexes are everywhere. 索引无处不在。

Thank you for any advice 谢谢你的任何建议

Your join would benefit from a composite 您的加入将受益于复合材料

job_offer_localitymap.(job_offerid,gps_localityid)

That is, going the opposite way than your present composite in that table. 也就是说,与该表中的当前组合相反。

As such you could drop these two: 因此,您可以删除以下两个:

  KEY `gps_localityid` (`gps_localityid`),
  KEY `job_offerid` (`job_offerid`),

As you would then be left with two composite indexes, with left-most of each used by other queries that benefited by the above two I just said to drop 然后,您将剩下两个复合索引,每个复合索引的最左端都由其他受益于上述两个的查询使用,我刚才说过删除


In your query line 5, be consistent and use the alias j as I had to hunt (not long) to see which table 在您的查询行5中,保持一致并使用别名j因为我必须搜寻(不长)以查看哪个表


In my opinion the KEY status ( status ) in job_offer might be relatively useless but I don't know you other queries. 我认为job_offer中的KEY statusstatus )可能相对没有用,但我不知道其他查询。 But as you datatypes are thin, a composite on job_offer(job_offerid,status) could make many of your queries fly, as it would be a covering index not needing to go after the datapage. 但是,由于您的数据类型很薄,因此job_offer(job_offerid,status)上的复合物可能会使您的许多查询飞起来,因为这将是一个covering index不需要在数据页之后。


As for job_offer_positionmap , that could be a join removing a slow subquery and developer choice for adding a composite there too. 至于job_offer_positionmap ,这可能是一个job_offer_positionmap ,它删除了慢的子查询,并且开发人员也选择在那里添加复合。 The join being similar to the first join, conceptually. 从概念上讲,该连接类似于第一个连接。


I see no problems with the in clauses in general, as the mysql CBO cost-based optimizer should deal with that. 我一般认为in子句没有问题,因为mysql CBO基于成本的优化器应该处理该问题。


But these are just suggestions, as adding indexes is not exactly without a downside. 但这只是建议,因为添加索引并非毫无缺点。 It is a fragile balancing act, but in the end you may find that not only does this query fly, but your others too. 这是一种脆弱的平衡行为,但最终您可能会发现此查询不仅会飞行,还会查询您的其他查询。


You are using the join for filtering. 您正在使用join进行过滤。 So I would move that logic to the where clause: 因此,我将该逻辑移至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;

Then, for this query, you want the following indexes: 然后,对于此查询,您需要以下索引:

  • job_offer(status, job_offerid desc) job_offer(状态,job_offerid描述)
  • job_offer_positionmap(cb_job_positionid, job_offerid) job_offer_positionmap(cb_job_positionid,job_offerid)
  • job_offer_localitymap(gps_localityid, job_offerid) job_offer_localitymap(gps_localityid,job_offerid)

The resulting query should use the first index for filtering and the order by clause. 结果查询应使用第一个索引进行过滤,并使用order by子句。 It will then use the other two indexes for filtering. 然后,它将使用其他两个索引进行过滤。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM