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

时间:2011-09-13 00:51:31

标签: 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>

这适用于大约500K记录。我使用的页面大小为5000,在第100页之后,查询开始显着减慢。第一个~80页是在2-3秒内提取的,但是在第130页左右之后,每个页面大约需要30秒才能检索,至少要到第200页。我的一个查询大约有900页,这需要太长时间。< / p>

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

我该怎么做才能加快速度?查询的说明显示了这个

select_type: SIMPLE
possible_keys: city
key : city
type: ref
key_len: 242
ref: const
rows: 4293720
Extra: using where; using filesort

如果有帮助,my.cnf for my server(24 GB ram,2 quad quad procs)有这些条目

  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

3 个答案:

答案 0 :(得分: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

以前不知道正弦页码,从值0开始并继续递增,直到查询返回null。您也可以执行选择计数(*),但这本身可能需要很长时间,并且无法帮助优化任何内容。一旦页码超过~60,每个查询大约需要2秒钟。

对我来说,页面大小是5000,所以我得到了位置0,5001,10001,15001的'name'字符串列表,依此类推。结果为1000的页数并将1000个结果列表存储在内存中并不昂贵。

现在,遍历列表并运行此查询

SELECT blobCol
FROM my_table
where name >= <pageHeader>
and name < <nextPageHeader>
and city="<any string>"
and id= 1

这将运行N次,其中N =先前获得的列表的大小。由于'name'是主键col,'city'也被编入索引,因此EXPLAIN显示此计算是使用索引在内存中执行的。

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

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

答案 1 :(得分:0)

您可以使查询更精确,因此限制更低。

SELECT col1,col2, col4 
FROM large_table
WHERE col1>"SomeKey" OR 
(col1="SomeKey" AND col2>="OtherKey")
ORDER BY col1,col2
LIMIT PageSize

但在每次数据库调用后更新“SomeKey”和“OtherKey”。

答案 2 :(得分:0)

我过去曾尝试使用Oracle 10g数据库并获得相同的结果(我的表有6000万行)。第一页被快速检索,但随着页码数量的增加,查询速度太慢。 由于索引看起来正确,因此您无法对索引进行任何操作,而且我不确定通过调整数据库配置可以实现的目标。 我想我有不同的要求,但我找到的唯一解决方案是将数据转储到文件中。 如果col1的值有限,则可以删除col1并生成n个表,每个表对应col1的每个已知值。如果col1未知,那么我不知道解决方案。 您可以从非常大的表中检索小数据集,但检索大量数据需要花费大量时间,而分页对您完全没有帮助。您必须通过转储到文件或生成其他表来分区数据进行预处理。