修复“Using where; Using temporary; Using filesort”问题

6

我有两个简单的表:

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

EXPLAIN说:

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

请告诉我有没有办法修复"Using where; Using temporary; Using filesort"并提高此查询的性能?


关于 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,您有什么想法? - juergen d
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 - Pavel
此查询执行时间非常长。 - Pavel
1个回答

2

看起来,由于某种原因,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字段时都会消耗处理器周期。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接