当前位置: 首页 > 知识库问答 >
问题:

每次后续调用,JPA分页查询都会变慢

惠泳
2023-03-14

该项目有JPA的Spring Boot。我们有一辆有100万条记录的台式车。表具有索引字段类型。

我们有一个用例,我们希望按类型获取所有记录。对于每种类型,我们都会得到所有的车辆记录,然后是下一种类型,然后是下一种,依此类推。

由于有100万条记录,我们将获取每种类型的记录,批量大小为1000。我们还应用了一个类型为column的过滤器

汽车仓库。JAVA

Page<VehicleRecord> findByType(String type, Pageable pageable);

车辆服务。JAVA

for (String type: vehicleTypes) {

  Pageable pageable = PageRequest.of(0, 1000, Sort.by("updated_at").ascending());
  Page<VehicleRecord> vehicles = null;

  do {
    vehicles = vehicleRepository.findByType(type, pageable);
    // do something with vehicles
    pageable = pageable.next();
  } while (vehicles.hasNext());

}

为了理解,假设有5种类型的记录:

  1. A-0车辆
  2. B-100000辆
  3. C-0车辆
  4. D-0车辆
  5. E-0车辆

问题:

>

  • 在这种情况下,当获取数据时,findByType在

    当取B时,第一次取LIMIT 1000 OFFSET 0需要大约200ms。但从这里开始走下坡路,随着OFFSET值的增加,时间也在增加。到LIMIT为1000和OFFSET 90000时,findByType需要6000-7000ms。

    更令人困惑的是,在为B获取数据之后,剩下的类型(C,D

    我不确定这里发生了什么。我在某处读到,这是因为高OFFSET值,该方法花费了这么多时间。但这并不能解释为什么这种方法需要花这么多时间来研究C、D和E。

    任何输入都会有帮助。谢谢

  • 共有1个答案

    党宇定
    2023-03-14

    Chris说了一句正确的话:应用程序不知道上次查询“B”时它离开了哪里,结果是(页面大小1000):

    您请求第0页:查找匹配的条目并将其添加到结果集中。一旦结果集的大小为1000,则返回它。

    您请求第1页:查找(!)并跳过前1000个匹配条目。将匹配的条目1001到2000添加到结果集中并忽略它。

    您请求第2页:查找(!)并跳过前2000个匹配条目。将匹配的条目2001到3000,添加到结果集中并忽略它。

    ...等等。

    因此,基本上数据库会多次执行查询,每次都会增加总查询时间,因为数据库不知道上次查询的位置。解决方案是以某种方式将最后获取的id(主键)传递给查询,然后从那里开始(…和id)

    我编译了一个示例应用程序来测试您的发现。在我的车辆表中,目前有723k项。数据库和应用程序在我的本地机器上运行(pagesize 1000):

    1. 查询A(0个条目)需要大约10ms。
    2. 查询B(0个条目)大约需要2200ms。
    3. 查询C(0个条目)需要大约10ms。
    4. 查询D(0个条目)需要大约10ms。
    5. 查询E(0个条目)需要大约10ms。

    所以,我无法重现你的问题。也许你可以将代码简化为尽可能简单的代码,并与我们分享(或者自己找到瓶颈)。

    我把我的上传到我的Github存储库。

    结果是:

    A: 185ms
    B: 2139ms
    B: 2007ms
    B: 1863ms
    B: 1930ms
    C: 2ms
    D: 3ms
    E: 2ms
    A: 1ms
    B: 2020ms
    B: 2044ms
    B: 2006ms
    B: 2053ms
    B: .. same average values all over
    

    还有一件事,如果数据库中有很多记录,但只有少量不同类型的记录,那么索引就不会有多大帮助。一些SQL优化器可能会忽略索引并执行完整表扫描,因为索引基数可能太低。

     类似资料:
    • 我正在为Kafka的客户librdkafka工作。lib在这里https://github.com/edenhill/librdkafka/blob/master/examples/rdkafka_example.cpp.每次调用Producer类中的product()时,是否调用dr\u cb()函数(请参见以下代码)?

    • 问题内容: 我正在使用 PhoneGap 开发移动应用程序,并且必须 从另一个项目 访问某些 服务 。我正在使用 jquery-2.0.0.js 和 jquery-mobile-1.3.2.js 。 这个ajax调用每次都会失败。在 config.xml中, 我有以下几行: 我可能在哪里错了! 问题答案: 问题在于您的phonegap应用程序正在从非网络服务器请求本地文件。本地文件交付时没有HTT

    • 问题内容: 我正在将Selenium WebDriver与Java一起使用。我试图访问该页面中的“登录ID”文本框,但是每次登录和注销时,针对“登录ID”文本框的XPath值都会更改,因此我无法检测到“登录ID”文本框每次都使用相同的代码。 我需要在代码中进行哪些修改,以便能够通过单个代码访问所有动态XPath? 问题答案: 以下是可能用作解决方法的示例 xpath的类型: 多个匹配项: 部分匹配

    • 问题内容: 每次调用时,React都会重新渲染所有组件和子组件吗? 如果是这样,为什么?我以为这个想法是,当状态改变时,React只渲染所需的内容。 在下面的简单示例中,尽管onClick处理程序始终将设置为相同的值,但是在随后的单击中状态不会改变,这两个类在单击文本时都再次呈现。 我曾希望只有在数据更改的情况下才会进行渲染。 这是示例代码,例如JS Fiddle和嵌入式代码段: 问题答案: 每次

    • 假设spring boot中有一个名为Person的类,其结构如下 人由一组电话号码组成。 是一个由上述字段组成的类,其中类别表示或等。 因此,每当我想要获取带有一些的详细信息时,我都会调用上面的方法,然后它应该获取详细信息,以及,其是。 方法应该是每当它在内部执行方法的查询时,它应该执行后续的查询来获取类别为的。我有没有办法得到上面提到的,或者有没有其他方法来实现它?请让我知道。 PS:如果在我