【问题标题】:Improve SORTING performance on long VARCHAR field提高长 VARCHAR 字段的排序性能
【发布时间】:2014-03-14 21:06:36
【问题描述】:

我有一个 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)

但它并没有提高性能。

我可以做些什么来改进这个查询?

解释

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 毫秒。

【问题讨论】:

  • 如果您想获得建议,请至少在此处发布您的表格结构(运行命令 show create table title 并在此处粘贴输出)
  • 这里只有一列很重要——composite_title
  • 如果您执行select * 并且您的键远小于用于排序的列,那么很可能索引不起作用。如果没有看到您的表格或explain 的输出(顺便说一下,不是排序查询本身,它是一个查询计划),就不能说更多。
  • 否,请参阅更新后的问题。
  • 尝试做一个explain ...query 它说什么?

标签: mysql performance


【解决方案1】:

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 或类似的大小,您可能会在不可预知的时间耗尽您的内存。

您可以逐个会话更改 sort_buffer_size。因此,您可以在全局范围内将其保留为默认大小,但在运行此类查询的会话中,增加它。

【讨论】:

  • 这里最长的电视节目是285个字符,所以上面的解决方案会截掉一些数据。还有其他想法吗?谢谢,
【解决方案2】:

尝试使用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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-04
    • 2011-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多