之前文章获取数据都是 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; } }
|
