提高long VARCHAR字段的SORTING性能

时间:2014-03-14 21:06:36

标签: mysql performance

我有一个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毫秒。

2 个答案:

答案 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