ThinkPHP6 业务分表之四:汇总

之前文章获取数据都是 O(1),但业务还是存在很多需要多表查的。

比如,用户登录,这时候我们是不清楚用户的记录是存放在哪个表的。

这里其实我很纠结要循环查还是用 union ,我们的结果只会在一个表中存在,或者全部表都不存在。循环的话可能会查 1 个,10 个,或者全部。union 就需要查全部了,但一定会有人告诉我们,不要在循环里面查数据库。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public function login(Request $request)
{
$username = $request->username;

$table_number = 16;

$uid = null;

for($i = 0; $i < $table_number; $i++) {
$uid = Db::table(sprintf('users_%x', $i))
->where('nickname', $username)
->value('id');

if(!is_null($uid)) {
break;
}
}

if(is_null($uid)) {
return '用户不存在';
}

return 'UID:' . $uid;
}

获取到查询结果后,可以做下缓存来减少查数据库的频率。

另外你可能发现这里存在问题了,nickname 在注册的时候是没有做唯一验证的,这块需要自行完善下,比如布隆过滤器。

接下来,我们获取下订单总金额排名前十位的用户。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public function top()
{
$table_number = 32;

$from_sql = '';

for($i = 0; $i < $table_number; $i++) {
if($i !== 0) {
$from_sql .= ' UNION ALL';
}

$from_sql .= sprintf(' SELECT * FROM `order_%x`', $i);
}

$sql = 'SELECT `uid` AS `id`, SUM(`amount`) AS `amount` FROM
( %s ) AS `a`
GROUP BY `uid`
ORDER BY `amount` DESC
LIMIT 10';

$sql = sprintf($sql, $from_sql);

$data = Db::query($sql);

foreach ($data as $item) {
echo sprintf('UID: %d,消费:%s', $item['id'], $item['amount']) . PHP_EOL;
}
}

往上