使用额外的ORDER BY优化两个大表上的JOIN

时间:2014-02-09 02:03:16

标签: mysql sql query-performance

我有两个非常大的表(第一个表是5 mio。条目,第二个表也是那么多行。) 第一个表objects有一个主键objectID 我的第二个表search有一个列searchID和一个列objectID,它引用了对象表中的objectID。

我现在想要的是,从我的对象表中获取所有对象,其中objectID在searchID = 1的搜索表中 searchID 1的行数非常大 - 大约有200万个条目。 我使用searchID / objectID组合的唯一键索引表。 查询如下所示:

SELECT *
FROM objects
JOIN search
ON search.searchID = 1
AND objects.objectID = search.objectID

此查询运行得非常快。 只要我不在ORDER BY或对象表格中的name添加title子句。 似乎任何指数都无济于事。 这个问题是否无法通过索引解决?我需要什么指数?

编辑:表格请求

TABLE `objects` (
  `objectID` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `title` varchar(255) NOT NULL,
  PRIMARY KEY (`objectID`),
  KEY `name` (`name`),
  KEY `title` (`title`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8

TABLE `search` (
  `searchID` int(11) NOT NULL,
  `objectID` int(11) NOT NULL,
  UNIQUE KEY `searchID` (`searchID`,`objectID`)
) ENGINE=InnoDB 
使用ORDER BY

EXPLAIN

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  search      ref     searchID,objectID   searchID    4   const   1014549 Using index; Using temporary; Using filesort
1   SIMPLE  objects     eq_ref  PRIMARY         PRIMARY 4   db_test.search.objectID     1   Using index
没有ORDER BY的

EXPLAIN

id  select_type table   type    possible_keys       key         key_len ref rows    Extra
1   SIMPLE  search      ref     searchID,contactID  searchID    4   const   1014549 Using index
1   SIMPLE  contact     eq_ref  PRIMARY             PRIMARY 4   db_test.search.objectID     1   Using index

1 个答案:

答案 0 :(得分:0)

首先你的查询不是很正确,正确的版本应该是:

SELECT *
FROM objects
INNER JOIN search
ON (objects.objectID = search.objectID and search.searchID = 1)

另一个版本:

SELECT *
FROM objects
where objects.objectID in (
    select search.objectID from search where search.searchID = 1)

从逻辑的角度来看,它们完全相同,但我不确定mysql是否会以相同的方式执行它们,所以测试两者并选择最快的一个

关于索引的下一期:

  1. 你真的需要从表中获取*,也许你可以减少到1/2列?
  2. 你真的需要varchar(255)吗?尝试减少到​​实际的字符串长度
  3. 在对象表上创建索引:INDEXNAME(SORTCOLUMN,objectid,其余列)
  4. 将表格类型更改为innodb,
  5. 增加sort_buffer_sizejoin_buffer_size
  6. 现在您可以将查询更改为其中一个(测试两者以选择最快)

    SELECT *
    FROM objects use index (INDEXNAME)
    INNER JOIN search
    ON (objects.objectID = search.objectID and search.searchID = 1)
    order by SORTCOLUMN
    

    SELECT *
    FROM objects use index (INDEXNAME)
    where objects.objectID in (
        select search.objectID from search where search.searchID = 1)
    order by SORTCOLUMN
    

    这就是我在测试数据库上得到的结果(解释扩展对于两个查询都是相同的):

    id  type    table   type    pk  key key_len ref                             rows    filter  Extra
    1   SIMPLE  objects index       srtcol  142                                 2091427 100.00  Using index
    1   SIMPLE  search  eq_ref  sid sid     5   const,testhash.objects.objectID 1       100.00  Using index
    

    注意:如果你需要这么长的字符串(varchar 255) - 你可以制作一个技巧:添加整数列,根据正确的顺序设置它的值,并对此列进行排序和索引

    这是我要测试的表格:

    CREATE TABLE `objects` (
      `objectID` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `sortcol` varchar(45) DEFAULT NULL,
      PRIMARY KEY (`objectID`),
      UNIQUE KEY `srtcol` (`sortcol`,`objectID`)
    ) ENGINE=InnoDB AUTO_INCREMENT=2490316 DEFAULT CHARSET=utf8;
    
    CREATE TABLE `search` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `searchID` int(10) unsigned NOT NULL,
      `objectID` int(10) unsigned NOT NULL,
      PRIMARY KEY (`id`),
      UNIQUE KEY `sid` (`searchID`,`objectID`)
    ) ENGINE=InnoDB AUTO_INCREMENT=2162656 DEFAULT CHARSET=utf8;
    

    每个都有大约2米的随机行