Получение старых балансов пользователей из системы с ~ 10 миллионами пользователей и txns после фильтрации, которые были неактивны, т.е. не имели txns - PullRequest
0 голосов
/ 11 января 2020

Это больше похоже на вопрос db.stackexchange, но здесь также можно найти решения для сценариев. Прошу прощения за отсутствие структуры в формулировке вопроса.

В таблицах участвуют -

Счет

CREATE TABLE `account` (
  `id` bigint(15) NOT NULL AUTO_INCREMENT,
  `account_id` bigint(14) NOT NULL,
  `acc_complete_id` bigint(14) DEFAULT NULL,
  `uuid` varchar(400) NOT NULL,
  `type` int(11) DEFAULT NULL,
  `created` datetime DEFAULT NULL,
  `balance` decimal(19,2) DEFAULT '0.00',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uuid_UNIQUE` (`uuid`),
  UNIQUE KEY `account_id_UNIQUE` (`account_id`),
  UNIQUE KEY `acc_complete_id_UNIQUE` (`acc_complete_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

Транзакция

CREATE TABLE `transaction` (
  `id` bigint(19) NOT NULL AUTO_INCREMENT,
  `type` int(4) DEFAULT NULL,
  `created` datetime DEFAULT NULL,
  `amount` decimal(19,2) DEFAULT '0.00',
  `debit` bigint(14) DEFAULT NULL,
  `credit` bigint(14) DEFAULT NULL,
  `status` varchar(45) DEFAULT NULL,
  `debit_bal` decimal(19,2) DEFAULT '0.00',
  `credit_bal` decimal(19,2) DEFAULT '0.00',
  PRIMARY KEY (`id`),
  KEY `transaction_credit_index` (`credit`),
  KEY `transaction_debit_index` (`debit`),
  KEY `transaction_created_index` (`created`),
  KEY `transaction_ref_index` (`ref`),
  KEY `transaction_narrative_index` (`narrative`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

Столбцы таблицы

  • debit_bal и credit_bal - это сальдо обоих счетов, участвующих в txn, после txn.

В настоящее время мы находим общее количество неактивных пользователей с нулевым балансом (бездействие, основанное на том, кто не совершал транзакции в течение определенного периода. Но сейчас самое болезненное то, что нам нужно получить эти данные за последние несколько месяцев (бездействие за это время и остатки на счетах du)

Используемый в настоящее время запрос для получения количества неактивных пользователей с нулевым балансом и некоторыми условиями на дату создания, тип и т. д. c. -

SELECT
  count(DISTINCT( a.uuid )),
  Sum(a.balance) 
FROM
  account a 
WHERE
  a.balance = 0.00 and a.type = "1" 
  AND a.created <= '2018-02-28 18:29:59' 
  AND 
  (
    a.account_id + 100000000000 
  )
  NOT IN 
  (
    SELECT DISTINCT
( pt.debit ) 
    FROM
      transaction pt 
    WHERE
      pt.created BETWEEN '2018-02-28 18:29:59' AND '2019-11-30 18:29:59' 
      AND MOD(pt.debit, 100000000000) IN 
      (
        SELECT
          pa.account_id 
        FROM
          account pa 
        WHERE
          pa.type = "1" 
          AND pa.created <= '2018-02-28 18:29:59' 
      )
    UNION
    SELECT DISTINCT
( pt.credit ) 
    FROM
      transaction pt 
    WHERE
      pt.created BETWEEN '2018-02-28 18:29:59' AND '2019-11-30 18:29:59' 
      AND MOD(pt.credit, 100000000000) IN 
      (
        SELECT
          pa.account_id 
        FROM
          account pa 
        WHERE
          pa.type = "1" 
          AND pa.created <= '2018-02-28 18:29:59' 
      )
  )

Над запросом возвращает количество неактивных пользователей с балансом примерно за 10 минут.

Неактивные пользователи = Пользователи - (набор пользователей, которые дебетовали пользователей UNION, которые сделали кредит).

Однако я не могу запустить этот запрос для старых месяцев, потому что значение, которое я получу, будет основано на текущих балансах, и тогда они не были одинаковыми. Типы учетных записей также, возможно, не были одинаковыми, но мы нашли их и обновили в дублирующей таблице.

Теперь, когда я пытаюсь подсчитать количество неактивных пользователей вместе с существующими балансами, удалив count () и добавив группу с помощью uuid, запрос выполняется более 15 часов, и в mysql состоянии потока в большинстве случаев показывается «удаление дубликатов».

Объяснить вывод -

+----+--------------------+------------+------------+-------------+------------------------------------------------------------------------------------------+----------------------------------+---------+------+----------+----------+----------------------------------------------+
| id | select_type        | table      | partitions | type        | possible_keys                                                                            | key                              | key_len | ref  | rows     | filtered | Extra                                        |
+----+--------------------+------------+------------+-------------+------------------------------------------------------------------------------------------+----------------------------------+---------+------+----------+----------+----------------------------------------------+
|  1 | PRIMARY            | a          | NULL       | ALL         | PRIMARY,uuid_UNIQUE,account_id_UNIQUE,acc_complete_id_UNIQUE,created_index,updated_index | NULL                             | NULL    | NULL | 23745634 |     5.00 | Using where; Using temporary; Using filesort |
|  2 | DEPENDENT SUBQUERY | pt         | NULL       | ref_or_null | transaction_debit_index,transaction_created_index                        | transaction_debit_index  | 9       | func |       32 |     7.52 | Using where                                  |
|  2 | DEPENDENT SUBQUERY | pa         | NULL       | eq_ref      | account_id_UNIQUE,created_index                                                          | account_id_UNIQUE                | 8       | func |        1 |     5.00 | Using index condition; Using where           |
|  4 | DEPENDENT UNION    | pt         | NULL       | ref_or_null | transaction_credit_index,transaction_created_index                       | transaction_credit_index | 9       | func |       22 |     7.52 | Using where                                  |
|  4 | DEPENDENT UNION    | pa         | NULL       | eq_ref      | account_id_UNIQUE,created_index                                                          | account_id_UNIQUE                | 8       | func |        1 |     5.00 | Using index condition; Using where           |
| NULL | UNION RESULT       | <union2,4> | NULL       | ALL         | NULL                                                                                     | NULL                             | NULL    | NULL |     NULL |     NULL | Using temporary                              |
+----+--------------------+------------+------------+-------------+------------------------------------------------------------------------------------------+----------------------------------+---------+------+----------+----------+----------------------------------------------+
6 rows in set, 1 warning (0.00 sec)

Теперь мне нужно получить список пользователей, который занимает много времени -

       SELECT DISTINCT
( a.uuid ),
  Sum(a.balance) 
FROM
  account a 
WHERE
  a.type = "1" 
  AND a.created <= '2018-02-28 18:29:59' 
  AND 
  (
    a.account_id + 100000000000 
  )
  NOT IN 
  (
    SELECT DISTINCT
( pt.debit ) 
    FROM
      transaction pt 
    WHERE
      pt.created BETWEEN '2018-02-28 18:29:59' AND '2019-11-30 18:29:59' 
      AND MOD(pt.debit, 100000000000) IN 
      (
        SELECT
          pa.account_id 
        FROM
          account pa 
        WHERE
          pa.type = "1" 
          AND pa.created <= '2018-02-28 18:29:59'
      )
    UNION
    SELECT DISTINCT
( pt.credit ) 
    FROM
      transaction pt 
    WHERE
      pt.created BETWEEN '2018-02-28 18:29:59' AND '2019-11-30 18:29:59' 
      AND MOD(pt.credit, 100000000000) IN 
      (
        SELECT
          pa.account_id 
        FROM
          account pa 
        WHERE
          pa.type = "1" 
          AND pa.created <= '2018-02-28 18:29:59'
      )
  )
GROUP BY
  a.id;

Это занимает почти 15 часов и продолжается до сих пор. Это слишком долго, потому что мне нужно сделать это в течение нескольких месяцев, и любая ошибка означает, что мне нужно запустить снова.

Некоторые примеры данных

Некоторые примеры данных -

Таблица счетов -

+------+------------+-----------------+---------------------+---------------------+---------------------+---------+
| id   | account_id | acc_complete_id | uuid                | last_updated        | created             | balance |
+------+------------+-----------------+---------------------+---------------------+---------------------+---------+
|   29 |      50536 |    100000050536 | 1026651502611722400 | 2020-01-09 12:43:49 | 2018-01-01 00:00:01 | 2092.10 |
| 1337 |      53071 |    100000053071 | 7266704751953077361 | 2019-12-26 11:45:54 | 2019-10-22 18:13:21 |   99.00 |
|   30 |      50673 |    100000050673 | 8799857402485889540 | 2020-01-05 13:21:16 | 2017-01-01 00:00:01 | 2166.10 |
+------+------------+-----------------+---------------------+---------------------+---------------------+---------+

Транзакция

+---------+---------------------+--------+--------------+--------------+-----------+------------+
| id      | created             | amount | debit        | credit       | debit_bal | credit_bal |
+---------+---------------------+--------+--------------+--------------+-----------+------------+
| 2001705 | 2019-12-07 14:14:18 |   1.00 | 100000050536 |            3 |   2092.00 | 2332445.91 |
| 2001869 | 2020-05-08 14:29:00 |   4.00 | 100000050673 | 200000052870 |   2088.10 |       4.00 |
| 2001874 | 2020-05-09 14:45:04 |   4.00 | 100000050673 | 200000052870 |   2084.10 |       8.00 |
| 2001875 | 2020-05-09 14:46:37 |   4.00 | 100000050673 | 200000052870 |   2080.10 |      12.00 |
| 2002018 | 2019-11-29 18:05:41 |  50.00 | 100000053071 | 300000050673 |      0.00 |    2170.10 |
| 2002019 | 2019-11-29 18:07:41 |   1.00 | 100000053071 | 300000050673 |    100.00 |    2170.10 |
| 2002020 | 2019-11-29 18:07:56 |   1.00 | 100000053071 |            5 |    100.00 |  580037.00 |
| 2002021 | 2019-11-29 18:15:22 |   1.00 | 100000053071 |            5 |    100.00 |  580037.00 |
| 2002022 | 2019-11-29 18:18:45 |   1.00 | 100000053071 |            5 |    100.00 |  580037.00 |
| 2002023 | 2019-11-29 18:20:41 |   1.00 | 100000053071 |            5 |    100.00 |  580037.00 |
| 2002024 | 2019-11-29 18:24:18 |   1.00 | 100000053071 |            5 |    100.00 |  580037.00 |
| 2002025 | 2019-11-29 18:26:19 |   1.00 | 100000053071 |            5 |    100.00 |  580037.00 |
| 2002026 | 2019-11-29 18:28:41 |   1.00 | 100000053071 |            5 |    100.00 |  580037.00 |
| 2002027 | 2019-11-29 18:29:37 |   1.00 | 100000053071 |            5 |    100.00 |  580037.00 |
| 2002028 | 2019-11-29 18:30:40 |   1.00 | 100000053071 |            5 |    100.00 |  580037.00 |
| 2002029 | 2019-11-29 18:35:55 |   1.00 | 100000053071 |            5 |    100.00 |  580037.00 |
| 2002030 | 2019-11-29 18:42:16 |   1.00 | 100000053071 |            5 |    100.00 |  580037.00 |
| 2002031 | 2019-12-02 13:12:01 |   1.00 | 100000053071 |            5 |    100.00 |  580037.00 |
| 2002032 | 2019-12-02 13:18:21 |   1.00 | 100000053071 |            5 |    100.00 |  580037.00 |
| 2002033 | 2019-12-02 13:27:53 |   1.00 | 100000053071 |            5 |    100.00 |  580037.00 |
| 2002034 | 2019-12-02 13:38:11 |   1.00 | 100000053071 |            5 |     99.00 |  580038.00 |
+---------+---------------------+--------+--------------+--------------+-----------+------------+

Суммирование

  • Итак, мне нужно получить список пользователей с их текущими балансами отсюда. Это узкое место, и я не могу думать о том, чтобы разбить эту часть, чтобы получить окончательный результат.

  • Как только у меня есть список таких пользователей с текущими балансами, я могу запросить другую таблицу общей суммы дебетовых и кредитных тксн против каждого пользователя в последующие месяцы, а затем выполните некоторое сложение и вычитание, чтобы получить старые балансы каждого пользователя, а затем сложите их, чтобы найти всех таких пользователей. Вряд ли в два месяца число пользователей txns увеличивается вдвое: 1078 *, поэтому эта часть происходит быстро.

Сейчас я думаю об альтернативах для получения данных. Обратите внимание, что мы изолировали эти таблицы, и теперь нет реального трафика c, поэтому мы можем добавить больше индексов, если это необходимо.

У меня не так много времени, чтобы экспериментировать с множеством подходов, но что Я думаю о следующем, чтобы добавить поля флага в таблицу учетной записи, например, «nov_inactive», «dec_inactive» et c. обозначает, где пользователь был неактивен в течение этого месяца. Я полагаю, что попытка обновить дублирующуюся таблицу с использованием тех же критериев выбора также потребует аналогичного времени -

update
  account_copy 
set
  nov_updates = 
  (
    1
  )
WHERE
  a.type = "1" 
  AND a.created <= '2018-02-28 18:29:59' 
  AND 
  (
    a.account_id + 100000000000 
  )
  NOT IN 
  (
    SELECT DISTINCT
( pt.debit ) 
    FROM
      transaction pt 
    WHERE
      pt.created BETWEEN '2018-02-28 18:29:59' AND '2019-11-30 18:29:59' 
      AND MOD(pt.debit, 100000000000) IN 
      (
        SELECT
          pa.account_id 
        FROM
          account pa 
        WHERE
          pa.type = "1" 
          AND pa.created <= '2018-02-28 18:29:59'
      )
    UNION
    SELECT DISTINCT
( pt.credit ) 
    FROM
      transaction pt 
    WHERE
      pt.created BETWEEN '2018-02-28 18:29:59' AND '2019-11-30 18:29:59' 
      AND MOD(pt.credit, 100000000000) IN 
      (
        SELECT
          pa.account_id 
        FROM
          account pa 
        WHERE
          pa.type = "1" 
          AND pa.created <= '2018-02-28 18:29:59'
      )
  )
GROUP BY
  a.id;

Есть мысли?

1 Ответ

0 голосов
/ 17 января 2020

Вот как мы вычислили старый баланс -

select count(account_id), sum(if(temp2.old_balance is null,temp1.balance, temp2.old_balance)) 
from
         (
          select 
           pa.account_id, pa.balance, temp.acc_id as acc_id from account as pa force index (created_index)
           left join
                   ((select mod(debit,100000000000) as acc_id from transaction where created BETWEEN '2018-02-28 18:29:59' AND '2019-11-30 18:29:59') 
                                  union 
                     (select mod(credit,100000000000) as acc_id from transaction where created BETWEEN '2018-02-28 18:29:59' AND '2019-11-30 18:29:59')
                    ) as temp
           on pa.account_id=temp.acc_id
           where pa.type = '1' AND pa.created <= '2018-02-28 18:29:59'
           having acc_id is null
          )
  as temp1
  left join 
  (
      select temp.acc_id,temp.txn_amt,b.balance,(b.balance-temp.txn_amt) as old_balance from  
      (
         select mod(temp.acc_id,100000000000) as acc_id, sum(if(type=1,temp.amount,0-temp.amount)) as txn_amt from 
         (
              select credit as acc_id,sum(amount) as amount, '1' as type from transaction where created > '2019-11-30 18:29:59' and status= "SUCCESSFUL" group by credit 
              UNION
              select debit as acc_id, sum(amount) as amount, '0' as type from transaction where created > '2019-11-30 18:29:59' and status= "SUCCESSFUL" group by debit
          ) as temp group by temp.acc_id
      ) as temp join account as b on temp.acc_id=b.account_id where b.created <= '2018-02-28 18:29:59' and type='1'
   ) as temp2 
   on temp1.account_id=temp2.acc_id

В псевдониме temp1 мы получаем текущий баланс, а в псевдониме temp2 мы получаем старый баланс тех пользователей, которые провели транзакции после отчетного месяца.

...