如何加速MySQL查询:按计数排序

时间:2012-09-26 06:42:19

标签: mysql performance tags aggregate

我已经尝试了一切我能想到的速度来加速这个查询,但它仍然需要大约2.5秒。

该表格为images_tags(约4百万行): 这是表EXPLAIN:

Field       Type               Null     Key     Default
image_ids   int(7) unsigned    NO       PRI     NULL
tags_id     int(7) unsigned    NO       PRI     NULL

以下是索引:

Table         Non_unique  Key_name      Seq_in_index  Column_name  Collation  Cardinality  Sub_part  Packed  Null  Index_type
images_tags   0           PRIMARY       1             image_ids    A          NULL         NULL      NULL          BTREE
images_tags   0           PRIMARY       2             tags_id      A          4408605      NULL      NULL          BTREE
images_tags   1           image_ids     1             image_ids    A          734767       NULL      NULL          BTREE

以下是查询:

select image_ids
from images_tags
where tags_id in (1, 2, 21, 846, 3175, 4290, 6591, 9357, 9594, 14289, 43364, 135019, 151295, 208803, 704452)
group by image_ids
order by count(*) desc
limit 10

这是查询EXPLAIN:

select_type  table        type   possible_keys  key                 key_len  ref   rows     Extra
SIMPLE       vids_x_tags  index  join_tags_id   join_vids_id_unique  8       NULL  4408605  Using where; Using index; Using temporary; Using filesort

目标是获得与这些标签最匹配的10张图片。 我试过搞乱这些变量几乎没有改进:

  • max_heap_table_size
  • tmp_table_size的
  • myisam_sort_buffer_size
  • read_buffer_size
  • sort_buffer_size的值
  • read_rnd_buffer_size
  • 的net_buffer_length
  • preload_buffer_size
  • 的key_buffer_size

有没有办法加快这个查询的速度?大约有700K图像并且它总是在增长,所以我不想将结果缓存超过一天或两天,并且必须为每个图像完成,所以重新缓存许多图像查询是不可能的。

2 个答案:

答案 0 :(得分:1)

在这种链接(结点,多对多)表中,在(a, b)(b, a)上都有两个复合索引几乎总是有用的。你只有一个(主要索引)而不是另一个。

如果表中没有其他列,则根本不需要任何其他索引。

因此,您应该添加(tags_id, image_ids)索引并删除(image_ids)多余的索引:

ALTER TABLE images_tags
  DROP INDEX image_ids,
  ADD INDEX tag_image_IDX           -- choose a name for the index
    (tags_id, image_ids) ;

关于特定查询的索引效率取决于很多因素,主要取决于图像和标签的分布(IN列表中的15个标签有多受欢迎?)

答案 1 :(得分:1)

在查询的EXPLAIN输出中,您会看到key列与possible_keys列表中的任何项都不匹配。这意味着虽然数据是从索引中获取的(在许多情况下,它比实际表小,因为它跨越较少的列),但引擎仍然必须遍历所有行。

如果您想要正确使用索引来加速此查询,则应添加一个标记为 first (可能只是)组件。

顺便说一下,image_ids上的索引只有一点用处,因为主键也可以用来提供这些信息。通常,可以使用多行索引来加速查询,这些查询为所有这些列提供显式值(或范围),或者从第一列开始提供连续的列集。换句话说,两列索引也会像第一列的单列索引一样,但它的第二列本身就没有多大用处,这就是你所拥有的。

作为在tags_id上添加密钥并在image_ids上删除密钥的替代方法,您可以将密钥保持在image_ids上,并反转列的顺序首要的关键。然后,主键也可用于回答仅标记查询。如果您通过标签而不是图像更频繁地查询表格,那么我建议采用这种方法。