在 select 查询 jooq 中使用 java 方法

Using a java method in select query jooq

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

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

以上查询在结果中将 ITEMDATA 与 ITEMMAMES table 连接到 select ITEMNAME。我正在内存中缓存 ITEMMAMES table,并希望避免与 ITEMMAMES table 的连接。这将加快查询速度并简化查询,因为实际查询要复杂得多。

我想用它类似于下面的东西。我想在 select 参数列表中调用 itemNamesCache.getItemName,它给出了 ITEMNAME 和 returns select 结果的一部分。 getItemName 应将响应中返回的 ITEMID 作为参数并给出 ITEMNAME。

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

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

您不能从 SQL 查询返回到某些 Java 逻辑,即使您正在使用 jOOQ 构建 SQL 查询(因此 Java) 让它看起来可行。

但是,您可以 post 通过使用先前构建的缓存修补记录来处理 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),这可以大大加快第二个查询的速度,具体取决于查询的数量distinct ITEMIDs(越小越好)。