Это больше похоже на вопрос 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;
Есть мысли?