我有一个composite_title
字段是VARCHAR(500)来保存电影或电视节目的标题。以下是一些示例:
- The Office, Season 1, Ep. 4 -- The Alliance
- BSG, Season 2, Ep. 3 -- Fragged
- Terminator
当我使用以下方式对该字段进行排序时:
select composite_title from title order by composite_title limit 10
速度很慢且不使用索引,它使用文件排序。我尝试添加类似的东西:
ALTER TABLE title ADD INDEX composite_title(10)
但它没有提高性能。
如何改善此查询?
EXPLAIN
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE title ALL NULL NULL NULL NULL 341353 Using filesort
更新:
数据库中最长的电视节目长度为285个字符。
根据Bill Karwin的解决方案,这对我有用:
ALTER TABLE `title` ADD `composite_title_for_sorting` VARCHAR(255) NOT NULL DEFAULT '';
UPDATE IGNORE title SET composite_title_for_sorting=composite_title;
现在,如果我按composite_title_for_sorting
排序,则查询需要1毫秒而不是500毫秒。
答案 0 :(得分:3)
MySQL应该使用索引进行排序,但如果索引是前缀索引,它似乎不喜欢这样做。
很明显,如果您的varchar长度太长,必须使用前缀索引。
因此,如果您想加快ORDER BY,最好的方法是将列的数据类型更改为可以支持非前缀索引的内容。 (你真的需要 varchar(500)吗?)
ALTER TABLE title MODIFY composite_tite VARCHAR(255), ADD KEY (composite_title);
然后你应该得到这个:
EXPLAIN SELECT composite_title FROM title ORDER BY composite_title\G
id: 1
select_type: SIMPLE
table: title
type: index
possible_keys: NULL
key: composite_title
key_len: 768 <-- this is the longest key_len allowed for an index
ref: NULL
rows: 100
Extra: Using index
另一个想法是创建第二列来存储字符串的缩短版本,然后索引该列。
如果您必须执行文件排序,那么增加sort_buffer_size
的大小可以减少在排序期间使用磁盘的依赖性,这将有助于提高性能。
但是如果你全局增加sort_buffer_size,请注意它是为查询期间排序的每个会话分配的,所以如果你将它设置为1GB或类似的东西,你可能会在不可预测的时间内耗尽内存。 / p>
您可以逐个会话地更改sort_buffer_size。因此,您可以将其保留为全局默认大小,但在运行此类查询的会话中,请增加它。
答案 1 :(得分:0)
尝试执行explain ...query
。请参阅此fiddle。
然后添加如下索引:
CREATE INDEX `helper` ON `title` (`composite_title`);
或
ALTER TABLE `title` ADD INDEX helper(`composite_title`);
然后重试您的查询:
SELECT composite_title
FROM title
USE INDEX(helper)
ORDER BY composite_title ASC
LIMIT 10;
MySQL优化器通常做出正确的选择。但有时它会做出错误的选择,或者不是最好的选择。所以我们强迫它。
但从技术上讲,您可以为要使用where
的列添加密钥。
也许有一些性能设置呢?
Set global thread_cache_size = 4;
Set global query_cache_size = 1024*1024*1024;
Set global query_cache_limit = 768*1024;
Set global query_cache_min_res_unit = 2048;
Set long_query_time = 5;
或者甚至可以在mysql中使用ElasticSearch。