[英]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_ref
, timestamp
和status
索引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.