【问题标题】:Using Filesort - Can't avoid it, even using index使用 Filesort - 无法避免,即使使用索引
【发布时间】:2012-10-07 23:18:56
【问题描述】:

我有一个包含 40,000,000 行的表,我正在尝试优化我的查询,因为耗时太长。
首先,这是我的桌子:
创建表resume (
yearMonth char(6) 默认为空,
type char(1) 默认为空,
agen_o char(5) 默认为空,
@987654325 @ char(2) 默认空值,
cve_ent char(1) 默认空值,
cve_mun char(3) 默认空值,
cve_reg int(1) 默认空值,
id_ope char(1) 默认空值,
ope_tip char(2) 默认空值,
ope_cve char(3) 默认空值,
cob_u int(9) 默认空值,tot_imp bigint(15) 默认为空,
) ENGINE=MyISAM 默认字符集=latin1;


这是我的查询:
SELECT m.name_ope AS cve,
SUBSTRING(r.yearMonth,5,2) 作为周期,
COUNT(DISTINCT(CONCAT(r.agen_ope,r.cve_ope))) AS num,
SUM(当 r.type='A' THEN r.cob_u ELSE 0 END)作为 tot_u,
FROM 简历 r,媒体 m
WHERE CONCAT(r.id_ope,SUBSTRING(r.ope_cve,3,1))=m.ope_cve AND
r.type IN ('C','D','E') AND
SUBSTRING(r.yearMonth,1,4)='2012' AND
r.id_ope='X' 和
SUBSTRING(r.ope_cve,1,2) IN (SELECT cve_med FROM catNac WHERE numero='0')
按子串分组(r.yearMonth,5,2),SUBSTRING(r.ope_cve,3,1)
按子串排序(r.yearMonth,5,2),子串(r.ope_cve,3,1)


所以,我添加了一个包含这些字段的索引:id_ope、yearMonth、agen_o,因为我有其他的查询在 WHERE 中有这个字段,按这个顺序
现在我的解释输出:
1 PRIMARY r ref indice indice 2 const 14774607 使用 where;使用文件排序
所以我用 yearMonth 添加了另一个索引 ope_cve,但我仍然有“使用文件排序”。我该如何优化呢?
谢谢

【问题讨论】:

  • MySQL 将无法使用索引,因为您正在使用函数(在本例中为 SUBSTRING)。
  • 非常感谢。我认为这可能是原因
  • 查看YearMonth字段,内容的格式是什么?是 2012 年 6 月的 201206 吗?
  • 没错。是 201201、201202 等等……

标签: mysql filesort


【解决方案1】:

在不修改表结构的情况下,如果年月有索引,可以试试这个:

SELECT m.name_ope AS cve,
SUBSTRING(r.yearMonth,5,2) AS period,
COUNT(DISTINCT(CONCAT(r.agen_ope,r.cve_ope))) AS num,
SUM(CASE WHEN r.type='A' THEN r.cob_u ELSE 0 END) AS tot_u,
FROM resume r, media m
WHERE CONCAT(r.id_ope,SUBSTRING(r.ope_cve,3,1))=m.ope_cve AND
r.type IN ('C','D','E') AND
r.yearMonth LIKE '2012%' AND
r.id_ope='X' AND
SUBSTRING(r.ope_cve,1,2) IN (SELECT cve_med FROM catNac WHERE numero='0')
GROUP BY r.yearMonth,SUBSTRING(r.ope_cve,3,1)

变化:

  • 使用r.yearMonth LIKE '2012%' 应该允许将索引用于where 子句的该部分。
  • 由于除了 2012 年之外,您每年都在过滤,因此您可以单独按 GROUP BY r.yearMonth 分组。
  • 不需要ORDER BY 子句,因为MySQL 对GROUP BY 进行排序,除非包含ORDER BY NULL

【讨论】:

  • 感谢您的观察...所以,我需要为 yearMonth 做另一个索引吗?而且,我需要订购或分组,首先是 SUBSTRING(r.yearMonth, 5, 2),即月份。仅按 y.yearMonth 分组,我将按年份而不是按月份分组结果,对吗?
  • 仅按年月分组,您将得到按年分组的结果,然后按月分组。但是由于您已经在 where 子句中按年份进行过滤,因此它将按 201201、201202... 等进行分组,因此它应该具有相同的结果。您的查询可以从索引中受益的唯一字段是id_opeyearMonthtype。您当前在 id_opeyearMonth 上的索引应该有助于此特定查询。
  • 你说得对,我不知道我没有注意到谁...谢谢你的帮助。最后一个问题,当我进行查询时,我的 CPU 达到 100%-200%,但我的内存几乎没有变化,就像 MySQL 使用 CPU 而不是内存......你知道可能是什么原因吗?
  • MySQL 将使用的内存量通常非常稳定,具体取决于您的配置。在这种情况下,它可能会尝试对内存中的所有数据进行排序/过滤,但我主要是在这里猜测。
  • 谢谢。我必须删除我的索引,因为我的查询需要更多时间,并且还会创建 tmp 表,没有索引就不要创建 tmp 表
猜你喜欢
  • 1970-01-01
  • 2014-07-17
  • 1970-01-01
  • 2019-01-12
  • 2013-12-27
  • 1970-01-01
  • 2013-02-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多