MySQL - 计算关系的最有效方法

时间:2016-08-10 11:44:32

标签: mysql join count bigdata

我在MySQL中有两个表。一个有accounts(4千万条记录),另一个有transactions(3亿条记录)。每天新增约20万笔交易。他们有一个1:n的关系:

+-----------------+
| Accounts        |
+----+------------+
| ID | account_no |
+----+------------+

+--------------------------------+
| Transactions                   |
+----+------------+--------+-...-+
| ID | account_no | amount | ... |
+----+------------+--------+-...-+

我需要编写SQL查询来创建按事务数量排序的accounts 列表。所以想到这样的事情:

SELECT a.account_no , COUNT(a.account_no) tx_count FROM accounts a
INNER JOIN transactions tx ON a.account_no = tx.account_no
GROUP BY tx.account_no ORDER BY tx_count DESC LIMIT 1000;

Link to SQLfiddle

我的问题:实现这一目标的最有效的方式是什么,因为我必须处理数以万计的记录?

[注意:字段account_no当然已编入索引]

2 个答案:

答案 0 :(得分:1)

你在寻求效率。所以坚持一张桌子,跳过JOIN。并且,使用COUNT(*)。它计算原始行。在计算COUNT(something_else)之前,something_else需要检查 SELECT account_no, COUNT(*) transaction_count FROM transactions GROUP BY account_no ORDER BY COUNT(*) DESC LIMIT 1000 值为null。 (http://sqlfiddle.com/#!9/cd6bb2/12/0

ORDER BY COUNT(*)

MyISAM访问方法可以直接从索引中满足此查询。 InnoDB必须扫描索引。

如果您的生产报告需要汇总的所有帐户而不是前1000个帐户,那么您可以考虑省略parent.component.ts ----------------------------------------- @Component({ template: ` <child dataset="{{ people }}"></child> `, }) export class ParentComponent{ private people: any[] = [ { name: 'jimmy', age: 22, gender: 'male' }, { name: 'johnny', age: 23, gender: 'male' }, { name: 'danny', age: 24, gender: 'male' } ]; } child.component.ts ----------------------------------------- export class ChildComponent implements OnInit{ @Input() private dataset: any[] = []; ngOnInit() { console.log(this.dataset); } } console ----------------------------------------- [object Object],[object Object],[object Object] 。这将节省一些时间在dbms。

Percona的人们对查询如何利用索引有很多极客的解释。例如:https://www.percona.com/blog/2012/11/23/full-table-scan-vs-full-index-scan-performance/

答案 1 :(得分:1)

要获得表现,您必须尽可能少地完成工作。

执行COUNT(*)不适合这种口头禅。

因此,如果您正在以有效的方式获得所追求的数字 - 请勿使用COUNT(*)。只需创建一个整数字段,其中包含Account中特定记录的计数,并使用触发器来处理递增/递减。可能听起来触发器会导致性能下降 - 他们不会在尝试获取每个帐户的交易计数时整个过程变得微不足道。

您可以为trx_count字段建立索引,您的查询将变为:

SELECT * FROM Accounts ORDER BY trx_count DESC;

表格变更:

ALTER TABLE Accounts add trx_count int unsigned  not null default '0';

Transactions

上插入触发器后
DELIMITER $$
CREATE

    TRIGGER `Transactions_after_insert` AFTER INSERT ON `Transactions` 
    FOR EACH ROW BEGIN
        UPDATE Accounts SET trx_count = trx_count + 1 WHERE id = new.account_no;
    END;
$$

DELIMITER ;

Transactions

上删除触发器后
DELIMITER $$
CREATE

    TRIGGER `Transactions_after_delete` AFTER DELETE ON `Transactions` 
    FOR EACH ROW BEGIN
             UPDATE Accounts SET trx_count = trx_count - 1 WHERE id = old.account_no;
    END;
$$

DELIMITER ;