[Spce-user] Fraud calculation takes hours

Alejandro Grijalba agrijalba at innovasur.es
Thu Jan 25 09:04:19 EST 2018


Hi.

I've got an instance with Sipwise version mr4.5.7 installed, and from 
time to time i get this query hogging the MySql server.
The server was upgraded from 2.8 (through 3.8) and we didn't notice the 
problem before.

There are 800k entries in cdr table (about 6 months wide), but all of 
them are older than 1 month (if that matters) because this is an upgrade 
test on a snapshot.

I have read that fraud calculation queries were already optimized in 
previous release, so what is wrong?
Thank you.


This is the query ( i guess it is generated from 
/usr/share/perl5/NGCP/Panel/Controller/API/CustomerFraudPreferences.pm ):

/* QUERY */

SELECT bpinfo.id, bpinfo.reseller_id, bpinfo.interval, bpinfo.type,
        IF (bpinfo.fraud_use_reseller_rates > 0, 
SUM(cdr.source_reseller_cost),
SUM(cdr.source_customer_cost)) as interval_cost,
        bpinfo.interval_limit,
        bpinfo.interval_lock,
        bpinfo.interval_notify,
        bpinfo.fraud_use_reseller_rates as use_reseller_rates
FROM (
   SELECT c.id, n.reseller_id, bp.fraud_use_reseller_rates, i.interval,
     IF (i.interval = 'month',
         IF (cfp.fraud_interval_limit > 0,
             'account_limit', 'profile_limit'),
         IF (cfp.fraud_daily_limit > 0,
             'account_limit', 'profile_limit')
        ) AS type,
     IF (i.interval = 'month',
         IF (cfp.fraud_interval_limit > 0,
             cfp.fraud_interval_limit, bp.fraud_interval_limit),
         IF (cfp.fraud_daily_limit > 0,
             cfp.fraud_daily_limit, bp.fraud_daily_limit)
        ) AS interval_limit,
     IF (i.interval = 'month',
         IF (cfp.fraud_interval_limit > 0,
             cfp.fraud_interval_lock, bp.fraud_interval_lock),
         IF (cfp.fraud_daily_limit > 0,
             cfp.fraud_daily_lock, bp.fraud_daily_lock)
        ) AS interval_lock,
     IF (i.interval = 'month',
         IF (cfp.fraud_interval_limit > 0,
             cfp.fraud_interval_notify, bp.fraud_interval_notify),
         IF (cfp.fraud_daily_limit > 0,
             cfp.fraud_daily_notify, bp.fraud_daily_notify)
        ) AS interval_notify
   FROM (SELECT IF('day' = 'month','month','day') AS 'interval') i,
        billing.contracts c
   INNER JOIN (
        SELECT bm1.contract_id,MAX(bm1.id) AS id
        FROM billing.billing_mappings bm1
        INNER JOIN (
               SELECT bm2.contract_id, MAX(bm2.start_date) AS start_date
               FROM billing.billing_mappings bm2
               WHERE (bm2.end_date >= NOW() OR bm2.end_date IS NULL)
                      AND (bm2.start_date <= NOW() OR bm2.start_date IS 
NULL)
               GROUP BY bm2.contract_id
        ) AS max ON bm1.contract_id = max.contract_id AND bm1.start_date 
<=> max.start_date
        GROUP BY bm1.contract_id
   ) AS bm_actual ON bm_actual.contract_id = c.id
   JOIN billing.billing_mappings bm ON bm.id = bm_actual.id
   JOIN billing.billing_profiles bp ON bp.id = bm.billing_profile_id
   JOIN billing.contacts n ON n.id = c.contact_id
   JOIN billing.resellers r ON r.id = n.reseller_id
   LEFT JOIN billing.contract_fraud_preferences cfp ON cfp.contract_id = 
c.id
   WHERE c.status = 'active'
   HAVING interval_limit > 0
) AS bpinfo
JOIN accounting.cdr ON cdr.source_account_id = bpinfo.id
WHERE CASE WHEN bpinfo.interval = 'month'
   THEN cdr.start_time
     BETWEEN UNIX_TIMESTAMP(DATE_FORMAT(NOW(), '%Y-%m-01 00:00:00'))
         AND UNIX_TIMESTAMP(DATE_FORMAT(NOW() + INTERVAL 1 MONTH, 
'%Y-%m-01 00:00:00'))-1
   ELSE cdr.start_time
     BETWEEN UNIX_TIMESTAMP(DATE_FORMAT(NOW(), '%Y-%m-%d 00:00:00'))
         AND UNIX_TIMESTAMP(DATE_FORMAT(NOW() + INTERVAL 1 DAY, 
'%Y-%m-%d 00:00:00'))-1
   END
GROUP BY bpinfo.id
HAVING interval_cost >= interval_limit
) `me`



More information about the Spce-user mailing list