【问题标题】:Fix Using where; Using temporary; Using filesort修复使用 where;使用临时的;使用文件排序
【发布时间】:2015-02-23 02:12:55
【问题描述】:

我有两个简单的表格:

CREATE TABLE cat_urls (
  Id int(11) NOT NULL AUTO_INCREMENT,
  SIL_Id int(11) NOT NULL,
  SiteId int(11) NOT NULL,
  AsCatId int(11) DEFAULT NULL,
  Href varchar(2048) NOT NULL,
  ReferrerHref varchar(2048) NOT NULL DEFAULT '',
  AddedOn datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  GroupId int(11) DEFAULT NULL,
  PRIMARY KEY (Id),
  INDEX SIL (SIL_Id, AsCatId)
)

CREATE TABLE products (
  Id int(11) NOT NULL AUTO_INCREMENT,
  CatUrlId int(11) NOT NULL,
  Href varchar(2048) NOT NULL,
  SiteIdentity varchar(2048) NOT NULL,
  Price decimal(12, 2) NOT NULL,
  IsAvailable bit(1) NOT NULL,
  ClientCode varchar(256) NOT NULL,
  PRIMARY KEY (Id),
  INDEX CatUrl (CatUrlId)
)

我有一个非常简单的查询:

SELECT cu.Href, COUNT(p.CatUrlId) FROM cat_urls cu
       JOIN products p ON p.CatUrlId=cu.Id
       WHERE sil_id=4601038
GROUP by cu.Id

解释说:

id  select_type table   type    possible_keys   key     key_len ref                     rows    Extra
1   SIMPLE      cu      ref     PRIMARY,SIL     SIL     4       const                   303     Using where; Using temporary; Using filesort
1   SIMPLE      p       ref     CatUrl          CatUrl  4       blue_collar_logs.cu.Id  6       Using index

请告诉我有什么方法可以修复“使用 where;使用临时;使用文件排序”并提高此查询的性能?

【问题讨论】:

  • explain select href, sum from cat_urls c join ( SELECT cu.id, sum(sil_id=4601038) as sum FROM cat_urls cu JOIN products p ON p.CatUrlId=cu.Id GROUP by cu.Id ) t on t.id = c.id怎么样
  • id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY <derived2> ALL (null) (null) (null) (null) 178525398 (null) 1 PRIMARY c eq_ref PRIMARY PRIMARY 4 t.Id 1 (null) 2 DERIVED cu index PRIMARY,SIL PRIMARY 4 (null) 29754233 (null) 2 DERIVED p ref CatUrl CatUrl 4 blue_collar_logs.cu.Id 6 Using index
  • 这个查询执行时间很长

标签: mysql temporary explain filesort


【解决方案1】:

看起来,出于某种原因,MySQL 选择在第一个表上使用索引 SIL,并将其用于查找 (WHERE sil_id = 4601038) 和分组 (GROUP BY cu.Id)。

你可以告诉它使用表的PK

SELECT cu.Href, COUNT(p.CatUrlId) FROM cat_urls cu
    USE INDEX FOR JOIN (PRIMARY)
JOIN products p ON p.CatUrlId=cu.Id
WHERE sil_id=4601038
GROUP by cu.Id

它会产生这个执行计划:

id | select_type | table | type  | possible_keys | key     | key_len | ref              | rows | Extra
---+-------------+-------+-------+---------------+---------+---------+------------------+------+-------------
1  | SIMPLE      | cu    | index | PRIMARY       | PRIMARY | 4       | NULL             | 1    | Using where
1  | SIMPLE      | p     | ref   | CatUrl        | CatUrl  | 4       | cbs-test-1.cu.Id | 1    | Using index

忽略rows列中报告的值;它们不正确,因为我的表是空的。

注意Extra 列现在只包含Using where,但也注意到连接type 列从ref(非常好)更改为index(全索引扫描,不太好)。

更好的解决方案是在列SIL_Id 上添加索引。我知道,SIL_Id 是索引SIL(SIL_Id, AsCatId) 的前缀,理论上SIL_Id 列上的另一个索引完全没用。但这似乎解决了这个案例的问题。

ALTER TABLE cat_urls
  ADD INDEX (SIL_Id)
;

现在在查询中使用它:

SELECT cu.Href, COUNT(p.CatUrlId) FROM cat_urls cu
    USE INDEX FOR JOIN (SIL_Id)
JOIN products p ON p.CatUrlId=cu.Id
WHERE sil_id=4601038
GROUP by cu.Id

查询执行计划现在看起来好多了:

id | select_type | table | type | possible_keys | key    | key_len | ref              | rows | Extra
---+-------------+-------+------+---------------+--------+---------+------------------+------+-------------
1  | SIMPLE      | cu    | ref  | SIL_Id        | SIL_Id | 4       | const            | 1    | Using where
1  | SIMPLE      | p     | ref  | CatUrl        | CatUrl | 4       | cbs-test-1.cu.Id | 1    | Using index

缺点是我们有一个(理论上)无用的额外索引。每次添加、删除或修改其SIL_Id 字段时,它都会占用存储空间并消耗处理器周期。

【讨论】:

    猜你喜欢
    • 2014-06-07
    • 2016-09-04
    • 2012-05-23
    • 2010-11-08
    • 2016-09-27
    • 2018-03-11
    • 1970-01-01
    • 2011-06-23
    • 1970-01-01
    相关资源
    最近更新 更多