簡體   English   中英

MySQL查詢從不同的值中查找計數

[英]MySQL query finding count from a distinct value

我有一個帶有58k交易記錄的表。 我只想帶回date參數(通常為1天)中3次付款被拒的Payment_ref(客戶ID)。 每天嘗試付款3次,只要其中一個被授權,我就會很高興。 我每天需要追逐的次數下降了3次。 我目前的查詢是

SELECT DISTINCT(cp.payment_ref) as ref
              , (SELECT COUNT(id) 
                   FROM client_payments 
                  WHERE status LIKE 'Declined' 
                    AND payment_ref = ref) as declined 
           FROM client_payments as cp 
          WHERE cp.payment_date BETWEEN '2018-05-14 00:00:00' AND '2018-05-14 23:59:59'

但是查詢需要很長時間,計數超過3(嵌入式查詢似乎在整個表中搜索),我在所有搜索字段上都有索引。 該表如下:

name , payment_ref, timestamp          , status
smith, 123        , 2018-05-15 10:12:22, Declined
smith, 123        , 2018-05-15 14:12:22, Declined
smith, 123        , 2018-05-15 19:12:22, Declined
john , 246        , 2018-05-15 10:12:22, Declined
john , 246        , 2018-05-15 14:12:22, Authorised (OK, 2nd payment is auth'd)
jones, 135        , 2018-05-15 10:00:22, Authorised (OK, 1st payment is auth'd)

我要去哪里錯了?

我看到不需要依賴子查詢來獲取計數,您可以從主查詢中獲取該計數,並消除所需計數的不同用途聚合

SELECT cp.payment_ref, COUNT(cp.id) cnt
FROM client_payments AS cp 
WHERE cp.payment_date BETWEEN '2018-05-14 00:00:00' AND '2018-05-14 23:59:59'
AND cp.`status` = 'Declined'
GROUP BY cp.payment_ref
HAVING cnt >= 3

還要檢查查詢的解釋計划並搜索是否使用了鍵/索引

似乎僅在count子查詢中需要時間范圍。

為什么不將where語句移到子查詢中? 這將大大減少運行時間:

SELECT DISTINCT(cp.payment_ref) as ref,
 (SELECT COUNT(id) FROM client_payments 
  WHERE status LIKE 'Declined' 
  AND payment_ref = ref
  AND payment_date BETWEEN '2018-05-14 00:00:00' AND '2018-05-14 23:59:59') as declined 
 FROM client_payments as cp 

在確保您有關於payment_reftimestampstatus索引payment_ref ,我將通過自我連接解決它:

SELECT @starttimestamp:='2018-05-14 00:00:00';
SELECT @endtimestamp:='2018-05-14 23:59:59';

SELECT
  first.payment_ref,
  first.timestamp, first.name, first.status,
  second.timestamp, second.name, second.status,
  third.timestamp, third.name, third.status
FROM
  transactions AS first

  -- find a later declined transaction
  INNER JOIN transactions AS second
    ON first.payment_ref=second.payment_ref
    AND first.timestamp<second.timestamp
    AND second.timestamp<=@endtimestamp
    AND second.status LIKE 'Declined%'

  -- find an even later declined transaction
  INNER JOIN transactions AS third
    ON second.payment_ref=third.payment_ref
    AND second.timestamp<third.timestamp
    AND third.timestamp<=@endtimestamp
    AND third.status LIKE 'Declined%'

WHERE first.timestamp BETWEEN @starttimestamp AND @endtimestamp
AND first.status LIKE 'Declined%'
;

這樣可以最佳利用索引,並且通過鍵范圍掃描具有很高的選擇性

如果確實需要逐行格式,則可以通過僅運行一次的包裝查詢來對其進行轉換。

謝謝您的回復。 最快的運行查詢如下.08秒

SELECT cp.payment_ref as ref,count(status='Declined') as no_declined FROM client_payments as cp WHERE cp.payment_date BETWEEN '2018-05-14 00:00:00' AND '2018-05-14 23:59:59' GROUP BY cp.payment_ref HAVING COUNT(status='Declined')>2

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM