我们正在改进网站周围的一些SQL查询,并注意到特定SQL查询的瓶颈似乎将结果转储到临时磁盘表中。这很昂贵,当然非常慢。
我们已经考虑将MySQL临时目录移到RAMDISK,但我们可以尝试先优化它。
以下是转储到磁盘的命令:
select
d.url,
d.lid,
d.title,
d.description,
d.date,
d.hits,
d.downloadratingsummary,
d.totalvotes,
d.totalcomments,
d.filesize,
d.version,
d.homepage,
d.ns_compat,
d.ns_des_img,
t.type
from downloads_downloads d
LEFT JOIN downloads_type t on d.lid = t.lid
where cid=91
ORDER BY FIELD(COALESCE(t.type,-1),1,-1,2,4,5,0,3), date DESC limit 0,20
有没有简单的方法来重新组织/修改上述查询以最小化磁盘上的临时表创建?
虽然我们有MySQL的经验,但性能优化对我们来说仍然是一个新的东西,所以任何人都可以给予的帮助总是非常感激。
感谢您提前提供任何帮助。
downloads_downloads
索引
downloads_type
索引
OS X运行带有16GB RAM的MySQL 5.5.23。
答案 0 :(得分:2)
我认为这些链接可以帮助优化此查询:
http://dev.mysql.com/doc/refman/5.5/en/order-by-optimization.html
http://dev.mysql.com/doc/refman/5.5/en/internal-temporary-tables.html
第一个结论 - 无法避免文件排序(临时表),因为ORDER BY
子句中的查询包含来自两个表的列,并且还包含表达式,因此mySql无法使用它来优化它指数:
在某些情况下,MySQL无法使用索引来解决ORDER BY ................这些情况包括以下内容:
- 将ORDER BY与包含键列名称以外的术语的表达式一起使用 - 您正在连接多个表,并且ORDER BY中的列不是来自用于检索行的第一个非常量表。
第二个结论 - 因为该表包含TEXT列,MySql不能使用修改的(优化)文件排序算法,但必须使用 oryginal 算法。 oryginal算法的一个缺点是它读取表行两次,并以随机方式读取它们,这比顺序读取慢得多:
这种方法的一个问题是它读取行两次:一次是在评估WHERE子句时,另一次是在对值对之后进行排序。即使第一次连续访问行(例如,如果进行了表扫描),第二次随机访问它们。 (排序键是有序的,但行位置不是。)
第三个结论 - 由于该表包含TEXT列,MySql不能使用内存临时表,但必须将其存储在磁盘上:
某些情况会阻止使用内存临时表,在这种情况下,服务器会使用磁盘表: - 表格中存在BLOB或TEXT列
考虑到上述情况,将TEXT列移到另一个表中:
create table downloads_description(
lid int(11) not null unique,
description text,
constraint dd_fk foreign key (lid)
references downloads_downloads( lid )
);
insert into downloads_description( lid, description )
select lid, description
from downloads_downloads;
alter table downloads_downloads
drop column description;
然后将查询重写为:
SELECT
d.url,
d.lid,
d.title,
dd.description,
d.date,
d.hits,
d.downloadratingsummary,
d.totalvotes,
d.totalcomments,
d.filesize,
d.version,
d.homepage,
d.ns_compat,
d.ns_des_img,
t.type
FROM downloads_downloads d
JOIN(
select d.lid, t.type
FROM downloads_downloads d
LEFT JOIN downloads_type t
ON d.lid = t.lid
WHERE cid = 81
ORDER BY FIELD(COALESCE(t.type,-1),1,-1,2,4,5,0,3),
d.date DESC
limit 0,20
) t ON d.lid = t.lid
JOIN downloads_description dd
ON dd.lid = d.lid
ORDER BY FIELD(COALESCE(t.type,-1),1,-1,2,4,5,0,3),
d.date DESC
;