java - 缓存查询结果

标签 java sql spring postgresql

假设我们有一个高度可配置的报告系统,它允许用户选择列、过滤器和排序。

所有这些配置都到达 BE,在那里它被转换为 SQL,针对 DB 执行,然后用户看到他的报告并可以继续使用它。但对于每个操作(例如排序),我们仍然构建一个查询。

转换本身需要几毫秒,但针对数据库的查询执行可能需要 3-5 秒(如果有大量并行执行,则最多需要 20 秒)。

所以,我正在考虑添加某种缓存。

目前,我看到三种方法:

  1. 添加一个表来缓存所有结果而不进行过滤,然后根据用户请求在 Java 端对其进行排序/过滤。
  2. 为每个结果添加一个表,但仍不带过滤器。在这种情况下,我将有可能对更少的数据进行排序/过滤,但有超过 10k 个不同的报告,我认为创建 10k 个小表不好。
  3. 与第一个选项类似,但 LRU 缓存在 Java 端。我们可以在内存中容纳 2-3k 报告结果。它通常比第一个选项更快,因为我们没有很多并行用户,只有拥有大量报告的用户。

每天会有几次缓存失效。

您认为加快速度的最佳方法是什么?从您的角度来看,提议的解决方案有哪些缺点和优点?如果可以自由选择数据库和技术(Java栈),你会怎么做?

最佳答案

好的,让我们确保我做对了。

there are more than 10k different reports

所以预先计算和预先缓存它们是没有意义的,它们必须按需生成。

there is not a lot of data in rows, just short strings, dates and integers. It’s not costly to fetch it in memory and even save there for a while

因此缓存少量数据可以避免代价高昂的大查询,这很好。

Add one table to cache all results without filtering, and then on user request sort/filter it on Java side.

问题是,很可能每个报告查询都会有不同的列,具有不同的名称,因此不能很好地适合单个表,除非您使用像 JSON 这样的格式,将每个缓存的结果行存储为 JSON 字典...在这种情况下,索引将是一个问题,即使您在 JSON 值内的字段上创建索引,如果您的许多报告中有无数个不同的列名称,您也将需要无数个索引...

闻起来像一 jar 蠕虫。

Add one table per result, still without the filters. In this case, I will have the possibility to sort/filter on much less amount of data, but there are more than 10k different reports, and I don't think it would be good to create 10k small tables.

优点:每个缓存表都可以有适当的列、数据类型和索引。使缓存失效很容易,截断它即可。您可以将所有缓存表设置为 UNLOGGED 以使其更快。您可以使用之前使用的相同 SQL 查询对缓存结果进行所有额外的排序/过滤,因此这可能是更简单的编码选项。如果您只想获取部分结果,那么分页也很好。就将报告查询的结果复制到缓存而言,这将是最快的选择,因为缓存已经在 postgres 中,不需要传输数据。您还可以将缓存存储在另一个驱动器/SSD 上。

缺点:我听说大量表的主要问题是文件系统在包含大量文件的目录上速度变慢。不过,这在现代文件系统上不应该是一个问题,而且我认为 postgres 本身根本不会被 10k 表所困扰。

这可能会使 information_schema 的查询变慢,并且 psql 中的“\dt”之类的东西会出现问题,因此缓存表最好隐藏在“缓存”模式中,这样它们就不会干扰。这也将使您更容易将它们从备份中排除。

它还会使用 postgres 服务器上的一些 RAM 来缓存缓存表,这取决于在线用户的数量。

我想说值得进行一些基准测试。创建一个架构,添加 10k 个表,看看是否有问题。

Like the first option, but LRU cache on Java side. We can fit in memory 2-3k report results. It will be usually faster than in the first option since we don't have a lot of parallel users, just users with lots of reports.

这有点重新发明轮子,你必须在 java 中重新实现排序/过滤器...加上缓存算法...meeeh。

还有其他选择:

  • 将缓存放在另一台计算机上的另一个数据库中。这可能是一个 postgres 实例,或另一个数据库(可能需要重写一些查询)。仅当缓存占用数据库上过多的 RAM 时才可能有趣。

  • 将缓存放入网络浏览器中,并使用 javascript 进行过滤/排序。根据互联网连接速度,这可能会更快,并且会减少服务器负载,但您必须编写大量 JavaScript 代码。

IMO,您对大量表持谨慎态度,谨慎是好事,但如果效果良好,这确实是最简单的解决方案...

关于java - 缓存查询结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59503147/

相关文章:

Java限制长度整数

mysql - SQL 分组合并未按预期工作

mysql - 帮助使用 SQL 查询查找预订系统的下一个可用日期

java - Spring BeanCreationException : Error creating bean with name

JAVA - 解析 XML 文件未正确存储数据

java - 使用 Spring Boot 为我的 Web 服务器创建客户端库,该库在 Android 应用程序中使用

java - Apache CXF/WSS4J 证书验证

java - 在 Spring MVC 中,无法使用 Jackson @JsonFormat 将输入绑定(bind)到日期字段

java - 为什么我们使用set方法

sql - PostgreSQL 8.2 : Require specific column to be present in UPDATE statement