【问题标题】:Using a java method in select query jooq在选择查询jooq中使用java方法
【发布时间】:2017-10-30 00:48:56
【问题描述】:

我有一个mysql查询,格式如下

        dslContext
            .select(
                ITEMDATA.ITEMID,
                ITEMDATA.COST,
                ITEMNAMES.ITEMNAME
            )
            .from(ITEMDATA)
            .join(ITEMNAMES)
            .on(ITEMDATA.ITEMID=ITEMNAMES.ITEMID)
            .where(conditions);

上述查询将 ITEMDATA 与 ITEMNAMES 表连接起来,以在结果中选择 ITEMNAME。我正在内存中缓存 ITEMNAMES 表,并希望避免与 ITEMNAMES 表连接。这将加快查询速度并简化查询,因为实际查询要复杂得多。

我想使用类似下面的东西。我想在提供 ITEMNAME 的选择参数列表中调用 itemNamesCache.getItemName 并返回选择结果的一部分。 getItemName 应该将响应中返回的 ITEMID 作为参数并给出 ITEMNAME。

    dslContext.
        select(
            ITEMDATA.ITEMID,
            ITEMDATA.COST,
            itemNamesCache.getItemName(valueOfItemId)
        )
        .from(ITEMDATA)
        .where(conditions);

P.S:我可以迭代结果并调用 itemNamesCache.getItemName。但如果可能的话,我想使用嵌入在查询中的东西

【问题讨论】:

  • 注意:ITEMDATA.ITEMID=ITEMNAMES.ITEMID 这实际上不起作用。您可能想使用eq() 方法

标签: java mysql jooq


【解决方案1】:

您不能将 SQL 查询回调回某些 Java 逻辑,即使您使用 jOOQ(以及 Java)构建 SQL 查询这一事实使其看起来可行。

但是,您可以通过使用先前构建的缓存修补记录来对 jOOQ 结果进行后处理:

Java 解决方案

如果您使用的数据库确实无法处理这种简单的连接(并且您已经检查过是否拥有所有正确的索引和约束!),那么您可以尝试以下解决方案:

// Assuming this import:
import static org.jooq.impl.DSL.*;

写...

Map<Integer, String> itemNamesCache =
dslContext.selectDistinct(ITEMNAMES.ITEMID, ITEMNAMES.NAME)
          .from(ITEMNAMES)
          .fetchMap(ITEMNAMES.ITEMID, ITEMNAMES.NAME);

dslContext
    .select(
        ITEMDATA.ITEMID,
        ITEMDATA.COST,
        // create an empty column here
        inline(null, String.class).as(ITEMNAMES.NAME))
    .from(ITEMDATA)
    .where(conditions)
    // fill the empty column with cached values
    .fetch(r -> r.value3(itemNamesCache.get(r.value1())));

基于 SQL 的解决方案

执行此操作的 SQL 方法是编写 correlated subquery

SELECT
  itemdata.itemid,
  itemdata.cost,
  (SELECT itemnames.name FROM itemnames WHERE itemnames.itemid = itemdata.itemid)
FROM 
  itemdata
WHERE
  ...

使用 jOOQ

// Assuming this import:
import static org.jooq.impl.DSL.*;

...写:

dslContext
    .select(
        ITEMDATA.ITEMID,
        ITEMDATA.COST,
        field(select(ITEMNAMES.NAME)
           .from(ITEMNAMES)
           .where(ITEMDATA.ITEMID.eq(ITEMNAMES.ITEMID)))
        .as(ITEMNAMES.NAME)
    )
    .from(ITEMDATA)
    .where(conditions)
    .fetch();

理论上,两个查询应该以完全相同的速度运行,因为它们是等效的(如果您在 ITEMDATA.ITEMID 上有一个外键)。

实际上,大多数数据库对于JOIN 查询可能会有更好的性能,除非它们实现标量子查询缓存(例如Oracle),这可以大大加快第二次查询的速度,具体取决于不同ITEMIDs 的数量(越小越好)。

【讨论】:

  • 我当然可以加入。但实际查询要复杂得多,涉及 5 个表。第一个原因是为了简化查询。第二个是查询性能。如果我避免加入,性能不会提高吗?
  • 5 个连接不是一个复杂的查询 :) 对于大多数数据库来说,这不是一个硬查询。试一试,测量一下,你会发现加入解决方案可能是最快的。
  • 我做了一个单一的连接,并测量了直接在数据库服务器上执行查询所花费的时间(忽略 java 层延迟)。没有连接,查询耗时 0.26 秒,有连接则耗时 0.58 秒。
  • 你有所有需要的索引吗?您是否多次运行查询以避免任何测量错误?您是否将该解决方案与我的相关子查询替代方案进行了比较?
  • 抱歉耽搁了。我已经准备好所有必需的索引并运行了几次。加入需要更多时间。子查询所用的时间几乎完全相同,相差 0.01 秒。
猜你喜欢
  • 1970-01-01
  • 2018-01-27
  • 1970-01-01
  • 1970-01-01
  • 2021-04-12
  • 2018-12-04
  • 2021-07-17
  • 2015-11-15
  • 2014-06-21
相关资源
最近更新 更多