我有一项任务是根据一些规则获取特定帐户和交易。值得注意的是,帐户和交易记录在不同的表中,我的查询返回的大部分是帐户-比例约为70个帐户对1笔交易。为了方便起见,我希望将它们放在一个查询中-这是更大过程的一个阶段。
原始查询:
SELECT DISTINCT
CASE
WHEN (a.transaction_type IN ('500', '501', '502', '920') AND a.transaction_date >= '#DATE#' AND to_char(a.transaction_date,'HH24') >= 16) THEN 'Transaction time'
WHEN b.closing_date >= '#DATE#' THEN 'Closing time'
WHEN b.opening_date >= '#DATE#' THEN 'Opening time'
WHEN (b.type = 'X' AND b.active = 'NO') THEN 'Frozen account'
END AS "comment"
,b.branch
,b.basic
,b.lmt
FROM
VDS.transactions a
JOIN VDS.accounts b ON a.acct_no = b.acct_no
WHERE
(a.transaction_type IN ('500', '501', '502', '920')
AND a.transaction_date >= '#DATE#'
AND to_char(a.transaction_date,'HH24') >= 16)
OR
(b.closing_date >= '#DATE#'
OR b.opening_date >= '#DATE#'
OR (b.type = 'X' AND b.active = 'NO'))
似乎运行良好,即使速度有些缓慢-它的执行时间通常约为12秒。问题是-有时根本无法完成。看起来数据库完全卡在了查询中。由于我不是Oracle管理员,所以我无法证实我怀疑这是该查询的错,但多项测试表明确实如此。
因此,考虑到交易比帐户少得多,我准备了另一种变体。
带有子查询的变量:
SELECT
'Transaction time' AS "comment"
,b.branch
,b.basic
,b.lmt
FROM
VDS.transactions a
JOIN VDS.accounts b ON a.acct_no = b.acct_no
WHERE
a.transaction_type IN ('500', '501', '502', '920')
AND a.transaction_date >= '#DATE#'
AND to_char(a.transaction_date,'HH24') >= 16
UNION
SELECT
CASE
WHEN closing_date >= '#DATE#' THEN 'Closing time'
WHEN opening_date >= '#DATE#' THEN 'Opening time'
WHEN (type = 'X' AND active = 'NO') THEN 'Frozen account'
END AS "comment"
,branch
,basic
,lmt
FROM
VDS.accounts
WHERE
closing_date >= '#DATE#'
OR opening_date >= '#DATE#'
OR (type = 'X' AND active = 'NO'))
本地化-缩短了执行时间到3-5秒,并且查询不再阻塞数据库。它还返回了更多的结果,这很奇怪,但不是问题。
所以我的最后一个问题是:有人可以向我解释数据库的胆量是什么,它很高兴地接受了子查询的变体,而原来的却变得不稳定了?我能更好地理解子查询的性能,但我不知道为什么查询有时会起作用,有时会完全挂断。
答案 0 :(得分:2)
实际上,这完全有道理...让我们看一下第一个查询的WHERE子句
WHERE
(a.transaction_type IN ('500', '501', '502', '920')
AND a.transaction_date >= '#DATE#'
AND to_char(a.transaction_date,'HH24') >= 16)
OR
(b.closing_date >= '#DATE#'
OR b.opening_date >= '#DATE#'
OR (b.type = 'X' AND b.active = 'NO'))
第一部分很简单...> =给定日期且具有某种交易类型的交易。没问题。
现在,您可以在“ B”帐户表测试的任何其他条件中为已打开,已关闭或冻结的帐户添加“或”。
由于(交易)“或”(帐户),您正在对最多“所有交易”(由于“或”)进行查询,因为您在比较最终“或”子句的冻结条件而不关心日期/时间。
由于将在一个帐户上进行交易以打开或关闭一个帐户,因此您知道该帐户将继续进行活动。如果在冻结帐户的交易中出现ATTEMPT,也将予以考虑。
这是我如何调整您的where子句...
WHERE
a.transaction_date >= '#DATE#'
AND to_char(a.transaction_date,'HH24') >= 16)
AND
( a.transaction_type IN ('500', '501', '502', '920')
OR
( b.closing_date >= '#DATE#'
OR b.opening_date >= '#DATE#'
OR (b.type = 'X' AND b.active = 'NO')
)
因此,您只考虑在预期日期范围内进行交易...,其中只有那些交易类型为OR(开放,关闭,冻结)的交易
答案 1 :(得分:2)
您的第二个查询将返回accounts
表中的多个结果,其中单行已重复并带有不同的注释(其中UNION
上方和下方的子查询都将其匹配)
但是,在第二个查询中,每个子查询的效率更高,因为第一个子查询可以在transaction
表上进行过滤,并且仅在过滤器已匹配且第二个子查询可以在JOIN
表上进行过滤,并且不需要account
,因此,在两者之间,不需要不必要的JOIN
。对于第一个查询,情况并非如此,因为JOIN
语句同时使用CASE
和account
表中的值,因此无论使用哪个过滤器,所有行都必须transaction
被赋值条件匹配。
另一种替代方法可能是不使用JOIN
而是使用JOIN
而是依靠EXISTS
语句的ELSE
子句来与{{1 }}过滤器已匹配,其他CASE
过滤器未匹配。
EXISTS
注意:这在OR
语句中具有不同的优先级,因此SELECT CASE
WHEN closing_date >= '#DATE#'
THEN 'Closing time'
WHEN opening_date >= '#DATE#'
THEN 'Opening time'
WHEN (type = 'X' AND active = 'NO')
THEN 'Frozen account'
ELSE 'Transaction time'
END AS comment,
branch,
basic,
lmt
FROM VDS.accounts a
WHERE closing_date >= '#DATE#'
OR opening_date >= '#DATE#'
OR ( type = 'X' AND active = 'NO')
OR EXISTS (
SELECT 1
FROM VDS.transactions t
WHERE a.acct_no = t.acct_no
AND t.transaction_type IN ('500', '501', '502', '920')
AND t.transaction_date >= '#DATE#'
AND to_char(t.transaction_date,'HH24') >= 16
)
可能会为您的查询提供不同的值-它们应该是第二个查询的返回行的子集,但是可能与第一个查询不匹配。
答案 2 :(得分:1)
查询的第一种形式仅在accounts表上使用带有条件的OR,因此,即使没有使用匹配的帐户,它也必须读取每个具有匹配帐户的交易。
在查询的第二种形式中,交易查询可以使用transaction_type
和transaction_date
上的索引(如果存在)(似乎在给定的域中),并且可以跳过不匹配的交易完全。
没有解释,这是猜测,但是第一个查询需要读取更多数据,因此可能无法使用索引,而第二个查询则不能使用索引。
您说查询返回的帐户多于交易。可能是这样,但是我怀疑总的交易量比帐户多吗?而且由于查询的第一种形式可能需要扫描事务表,因此不管它们是否匹配,都关系到表的大小。