使用非索引列的SQL计数查询

时间:2013-09-05 15:54:35

标签: sql performance oracle

我有类似的查询,我需要查找特定客户在一个时间范围内的交易数量:

select customer_id, count(transactions)
from transactions
where customer_id = 'FKJ90838485'
and purchase_date between '01-JAN-13' and '31-AUG-13'
group by customer_id

表事务未在customer_id上编制索引,而是另一个名为transaction_id的字段。 Customer_ID是字符类型,而transaction_id是数字。

'accounting_month'字段也被编入索引..此字段仅存储交易发生的月份...即,purchase_date = '03 -MAR-13'将具有accounting_month = '01 -MAR-13'

交易表在'01 -JAN-13'和'31 -AUG-13'的时间范围内有大约2000万条记录

当我运行上述查询时,它需要超过40分钟才能回来,有任何想法或提示吗?

3 个答案:

答案 0 :(得分:4)

正如其他人已经评论过的那样,最好是添加一个覆盖查询的索引,所以:

  • 请与数据库管理员联系并请求他们在(customer_id, purchase_date)上添加索引,因为查询正在执行表扫描。

图片的标题说明:

  • 使用日期而不是字符串文字(您可能已经知道并且已经这样做了,这里仍然为未来的读者注意)
  • 您不必将customer_id放在SELECT列表中,如果从那里删除它,也可以从GROUP BY删除它,以便查询变为:

    select count(*) as number_of_transactions
    from transactions
    where customer_id = 'FKJ90838485'
      and purchase_date between DATE '2013-01-01' and DATE '2013-08-31' ;
    
  • 如果您在WHERE上没有customer_id条件,则可以在GROUP BYSELECT列表中创建select customer_id, count(*) as number_of_transactions from transactions where purchase_date between DATE '2013-01-01' and DATE '2013-08-31' group by customer_id ; 条件将计算每个客户的交易数量。以上建议的指数也有助于此:

    {{1}}

答案 1 :(得分:0)

这只是我想到的一个想法。它可能会起作用,尝试运行它,看看它是否比你现有的有所改进。

我正在尽可能地使用你所说的transaction_id索引。

WITH min_transaction (tran_id)
AS (
   SELECT MIN(transaction_ID)
   FROM TRANSACTIONS
   WHERE
      CUSTOMER_ID = 'FKJ90838485'
      AND purchase_date >= '01-JAN-13'
   ), max_transaction (tran_id)
AS (
   SELECT MAX(transaction_ID)
   FROM TRANSACTIONS
   WHERE 
      CUSTOMER_ID = 'FKJ90838485'
      AND purchase_date <= '31-AUG-13'
   )
SELECT customer_id, count(transaction_id)
FROM transactions
WHERE
   transaction_id BETWEEN min_transaction.tran_id AND max_transaction.tran_id
GROUP BY customer_ID

答案 2 :(得分:0)

这可能会更快,因为它会查看范围的transaction_id而不是purchase_date。我还考虑到accounting_month被编入索引:

select customer_id, count(*)
from transactions
where customer_id = 'FKJ90838485'
and transaction_id between (select min(transaction_id)
                            from transactions
                           where accounting_month = '01-JAN-13' 
                           )  and
                           (select max(transaction_id)
                            from transactions
                           where accounting_month = '01-AUG-13' 
                           ) 
group by customer_id 

也许你也可以尝试:

select customer_id, count(*)
from transactions
where customer_id = 'FKJ90838485'
and accounting_month between '01-JAN-13' and '01-AUG-13'
group by customer_id