我有一个信用变动的架构,如下所示:
id | orderno | due | bookingdate | movementtype
=================================================
1 | o11 | 30.50 | 10.01.2017 | CREDIT
2 | o22 | 50.99 | 11.01.2017 | DEBIT
3 | o11 | 20.40 | 12.01.2017 | DEBIT
4 | o22 | 77.88 | 13.01.2017 | CREDIT
5 | o11 | 05.20 | 14.01.2017 | DEBIT
我想检索给定订单号和年份的CREDIT总额减去DEBIT。
因此,对于上面的虚拟数据,通过orderno=o11
和booking=2017
,我希望4.9
。
我提出了一个包含两个子查询的查询:
SELECT
(credit - debit) AS total
FROM
(
SELECT
COALESCE(SUM(due), 0.0) AS credit
FROM
accountactivity
WHERE
orderno = :ordernoParam
AND YEAR(bookingdate) = :bookingParam
AND movementtype = 'CREDIT'
),
(
SELECT
COALESCE(SUM(due), 0.0) AS debit
FROM
accountactivity
WHERE
orderno = :ordernoParam
AND YEAR(bookingdate) = :bookingParam
AND movementtype = 'DEBIT'
)
问题:是否可以针对我的任务优化查询?出于性能原因,我想避免子查询。它应该适用于DB2和Oracle 11g,可以通过本机查询,也可以通过HibernateQL。
答案 0 :(得分:1)
我会使用CASE
SELECT
COALESCE(SUM(CASE WHEN movementtype = 'CREDIT' THEN due END), 0.0) -
COALESCE(SUM(CASE WHEN movementtype = 'DEBIT' THEN due END), 0.0) AS total
FROM
accountactivity
WHERE
orderno = :ordernoParam
AND YEAR(bookingdate) = :bookingParam
如果您的覆盖索引accountactivity(orderno)
包含bookingdate
,movementtype
和due
属性,则应通过一次范围扫描执行。
可以优化的另一个问题是YEAR(bookingdate) = :bookingParam
条件。查询处理器不能使用它来搜索索引中的查找操作。如果您将其重写为bookingdate >= CAST('1.1.' + :bookingParam AS DATE) and bookingdate <= CAST('31.12.' + :bookingParam AS DATE)
(这可能是特定于DBMS的),那么您可以拥有包含accountactivity(orderno, bookingdate)
和movementtype
属性的索引due
,并且范围扫描将会读取只有相关的行。