处理大量具有分页的数据库条目随着时间的推移而减慢

ran*_*ght 7 java mysql database hibernate

我正在尝试从我的表中处理数百万条记录(大小约为30 GB),我目前正在使用分页(mysql 5.1.36).我在for循环中使用的查询是

select blobCol from large_table 
where name= 'someKey' and city= 'otherKey' 
order by name
LIMIT <pageNumber*pageSize>, <pageSize>
Run Code Online (Sandbox Code Playgroud)

这适用于大约500K记录.我使用的页面大小为5000,在第100页之后,查询开始显着减慢.第一〜80页中提取2-3秒,但大约130页之后,每个页面大约需要30秒来检索,至少要等到页面200我的一个查询的大约有900页,这将花费太长时间.

The table structure is (type is MyISAM)
    name char(11)
    id int // col1 & col2 is a composite key
    city varchar(80) // indexed
    blobCol longblob
Run Code Online (Sandbox Code Playgroud)

我该怎么做才能加快速度?查询的解释显示了这一点

select_type: SIMPLE
possible_keys: city
key : city
type: ref
key_len: 242
ref: const
rows: 4293720
Extra: using where; using filesort
Run Code Online (Sandbox Code Playgroud)

如果它有帮助,我的服务器my.cnf(24 GB RAM,2四核处理)有这些条目

  key_buffer_size = 6144M
  max_connections = 20
  max_allowed_packet = 32M
  table_open_cache = 1024
  sort_buffer_size = 256M
  read_buffer_size = 128M
  read_rnd_buffer_size = 512M
  myisam_sort_buffer_size = 128M
  thread_cache_size = 16
  tmp_table_size = 128M
  max_heap_table_size = 64M
Run Code Online (Sandbox Code Playgroud)

ran*_*ght 2

这是我所做的,将总执行时间减少了 10 倍。

我从原始查询的执行计划中意识到,它使用 filesort 对所有结果进行排序并忽略索引。这有点浪费。

我的测试数据库:5 M 记录,20 GB 大小。表结构与问题中相同

我没有在第一个查询中直接获取 blobCol,而是首先获取每个页面开头的“name”值。无限期地运行此查询,直到返回 0 个结果。每次,将结果添加到列表中

SELECT name
FROM my_table
where id = <anyId> // I use the id column for partitioning so I need this here
order by name
limit <pageSize * pageNumber>, 1
Run Code Online (Sandbox Code Playgroud)

正弦页码之前未知,从值 0 开始并不断递增,直到查询返回 null。您还可以执行 select count(*) 但这本身可能需要很长时间并且无助于优化任何内容。一旦页码超过 ~60,每个查询运行大约需要 2 秒。

对我来说,页面大小为 5000,因此我在位置 0、5001、10001、15001 等处获得了“名称”字符串列表。结果页数为 1000,并且在内存中存储 1000 个结果的列表并不昂贵。

现在,迭代列表并运行此查询

SELECT blobCol
FROM my_table
where name >= <pageHeader>
and name < <nextPageHeader>
and city="<any string>"
and id= 1
Run Code Online (Sandbox Code Playgroud)

这将运行 N 次,其中 N = 先前获得的列表的大小。由于“name”是主键 col,并且“city”也已建立索引,因此 EXPLAIN 表明该计算是使用索引在内存中执行的。

现在,每个查询运行需要 1 秒,而不是原来的 30-40 秒。因此,结合每页 2 秒的预处理时间,每页总时间为 3-4 秒,而不是 30-40 秒。

如果有人有更好的解决方案,或者如果这个解决方案有明显的错误,请告诉我