我在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;
我的问题:实现这一目标的最有效的方式是什么,因为我必须处理数以万计的记录?
[注意:字段account_no
当然已编入索引]
答案 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 ;