如何在结果集中获取WHERE条件评估的结果?

时间:2009-06-26 21:23:48

标签: java sql mysql

问题

我有这样的查询:

select a.id from a join b on ( a.id = b.my_a ) join ....
where 
    ( /* complex and expensive conditional */ )
    AND 
       (( /* conditional #1 */ ) 
        OR ( /* conditional #2 */ )
        OR ( /* conditional #3 */))

我想让查询返回类似的内容:

select a.id, conditional_1_eval_value, conditional_2_eval_value, conditional_3_eval_value from a join b on ( a.id = b.my_a ) join ....
where 
    ( /* complex and expensive conditional */ )
    AND 
       (( /* conditional #1 */ ) 
        OR ( /* conditional #2 */ ) 
        OR ( /* conditional #3 */))

其中conditional_1_eval_valueconditional_2_eval_valueconditional_3_eval_value设置为TRUE,FALSE,NULL。 NULL表示未评估条件。

所以结果集可能是:

1, FALSE, NULL, TRUE ( condition_1, condition_3 were evaluate, condition_2 was not)
2, NULL, TRUE, TRUE ( condition_2, condition_3 were evaluate, condition_1 was not)
3, TRUE, FALSE, FALSE (all were evaluated)

condition_1condition_2condition_3本身很复杂,涉及相关子查询和分组。

编辑:

我想要完成什么?

我们需要记录导致返回行的条件。我们不需要知道返回行的所有原因。因此,在结果示例的第二行中,知道conditional_2conditional_3都是真的就足够了。不知道conditional_1值是什么并不重要。

足以知道至少有一个条件满足,条件是什么条件。

非最佳解决方案

显然,我可以使用 UNION 这样做:

select a.id, TRUE, NULL, NULL from a join b on ( a.id = b.my_a ) join ....
where 
    ( /* complex and expensive conditional */ )
    AND 
       ( /* conditional #1 */ )
UNION
select a.id, NULL, TRUE, NULL from a join b on ( a.id = b.my_a ) join ....
where 
    ( /* complex and expensive conditional */ )
    AND 
        ( /* conditional #2 */ )
UNION
select a.id, NULL, NULL, TRUE from a join b on ( a.id = b.my_a ) join ....
where 
    ( /* complex and expensive conditional */ )
    AND 
        ( /* conditional #3 */)

但这意味着:

  1. 常见的“复杂且昂贵的条件”被评估3次。
  2. 即使另一个条件已满足OR,也会评估所有条件。
  3. 会有一个维护噩梦,确保常见的复杂查询的3个副本是相同的(可以通过在代码中构造sql并复制公共字符串来解决 - 但这意味着我会违反所有sql的另一个内部标准而不是嵌入在java中,但在可见到DBA的XML文件中)
  4. 在选择中使用 CASE复制每个条件1到3可避免共同条件被评估3次。然而,条件1-3的复杂性使得它可能是不可能的。

    在FROM 子句中使用 select会很尴尬,可能无法实现,因为FROM SELECT不能是相关查询。我不确定我是否可以构建一个有用的非相关查询。

    存储过程可行。但是,这将是第一个这样的存储过程,并且会显着增加我们的部署复杂性。

    在java代码中执行conditional_1conditional_2conditional_3评估。这就是我们目前正在做的事情,它运行的是sloooooooow。当数据库被设计为过滤结果集时传输的大量数据 - 不应该在java中执行此操作!

    解决方案建议?

    任何?

    我还应该补充一点,我欢迎那些说这个问题无法解决的答案。知道问题无法解决将节省我尝试用严格的SQL解决它的时间。

    如果我必须选择,我会倾向于学习mysql存储过程的样子。

    所以,如果你想自愿提供mysql存储过程看起来会很棒的东西。

5 个答案:

答案 0 :(得分:2)

要实现您的目标,为什么不在复杂条件下使用存储函数?

这将导致选择语句,如:


select func1(arg1, arg2, ...), func2(arg1, arg2, ...), rest_of_select_columns 
from table1, table2
where (complex1 logic) 
OR func1(arg1, arg2, ....) = 1 /* return to give true */ 
OR func2(arg1, arg2, ....) = 1 

注意:

  1. SQL不支持布尔数据类型,所以true,false,因为函数的结果是不可能的。因此,0,1返回值。
  2. 根据您的mySQL版本,您可以使功能DETERMINISTIC,这可能会带来一些性能提升。

答案 1 :(得分:1)

Franky,我不知道如何在MySQL(或实际上在任何SQL)中表达问题。但是,几年前我还面临着同样复杂,庞大的数据集评估问题 1

根据所收集的经验,我可以就如何加快评估提出一些想法:

  • 我会考虑切换到另一个数据库引擎(替换当前的数据引擎或只是将数据复制到其中) - 我会使用Oracle,因为我知道它在查询优化方面的能力。其他选择是使用嵌入式sql引擎使数据更接近计算位置。
  • 我将再次了解当前基于Java的评估。也许调整查询批量大小,对问题中涉及的各种表进行并行纠缠查询,并使用基于流的方法。
  • 如果我的Java代码有一些可用的内存,我会考虑在需要频繁执行计算时始终将部分/全部数据缓存在内存中。
  • 或者寻找一种方法来消除条件的共同部分,通过在条件之间共享来获得一定的速度。

1 实际上,约束是在~1M记录集上进行快速按需计算。

答案 2 :(得分:1)

你是正确的,将所有数据拉回到java并执行你的条件将是一只狗。

但是,你真正的选择是联合3种不同的查询。由于关系引擎如何工作,所以无法取出记录中的“命中”。

答案 3 :(得分:0)

您是否可以选择与结果相关的所有数据,然后在客户端代码中执行结果集中的条件逻辑?

答案 4 :(得分:0)

如果您希望减少复杂表达式的重新输入,请将表达式放在子查询派生表中:

SELECT t.*
FROM (
    SELECT a.*, b.*, ...
        /* conditional #1 */ AS c1,
        /* conditional #2 */ AS c2,
        /* conditional #3 */ AS c3
    FROM a JOIN b ON (a.id = b.my_a)
    ...) AS t
WHERE /* ...other conditions... */
    AND ((c1) OR (c2) OR (c3));

这也是一个不同问题的解决方案,“如何在WHERE条件中使用列别名?”