前言
在分表完之后显然对于数据的查询会变的比较的复杂,特别是在表的关联方面,在有些情况下根本就不能使用JOIN。
其实个人是比较鼓励将那些大的JOIN SQL拆分成几个小的SQL来查询数据。这样虽然总体的效率可能会稍稍下降(如果使用了连接池完全可以忽略),但是查询的语句变简单了,使得后续的维护带来的方便。同时也能带来比较便利的扩展。你可以感受一下有一个100行的SQL语句给你维护,和给你10个10行并且每一块都有很好的注释的SQL去维护,去帮助调优。你愿意选哪个。不管你们信不信,反正我是选第二种,而且第二种可以很好的理解业务。
上面说到要拆分JOIN,我的意思不是将每个语句都拆分。我的准则是 O(n) 次的查询。忌讳那种查出数据后通过程序循环查出结果再去数据库中查询,也就是需要 O(n*M)这种。 瞬间感觉方法论很重要有木有 ^_^。
模拟场景
场景1:购买者下订单
1、在浏览商品的时候能获得商品的 门店ID 和 商品ID,至于导购ID这里我们能以随机的形式得到(需要根据业务来确定如何获取导购ID)
2、通过导购ID获得导购的用户信息从而得到导购的数据应该放在那张分表。
3、将下单数据存入出售者的分表,和购买者的分表。
下面展示的是伪代码(因为只用SQL不好展示具体业务逻辑),其实是自己比较懒不想写Python了。^_^
-- 获得导购分表信息,和所在门店
SELECT u.table_flag AS guide_flag,
ug.store_id AS store_id
FROM user AS u, user_guide AS ug
WHERE u.user_id = ug.user_id
AND user_guide_id = 导购ID;
SET autocommit=0;
START TRANSACTION;
-- 创建销售订单 sell_order_2 通过程序拼凑出来的
INSERT INTO sell_order_2
VALUES(order_SnowflakeID, 导购ID, 购买者ID, 订单总额, 订单状态);
-- 记录此订单有哪些商品
INSERT INTO order_goods_2
VALUES(order_goods_SnowflakeID, order_SnowflakeID, 商品ID, 商品价格, 商品个数);
-- 记录购买订单表 buy_order_6 购买者所在的分表,上面的是出售者所在的分表别弄混了
-- 购买者订单ID 和 出售者订单ID是一样的
INSERT INTO buy_order_6
VALUES(order_SnowflakeID, 用户ID, 导购ID)
COMMIT;
SET autocommit=1;
情况2:购买者浏览订单
浏览购买者订单就是比较麻烦的,因为购买者订单信息和商品信息不是在同一分表中。
1、分页查找出购买者的订单列表。
2、将订单信息返回给浏览器后,使用ajax获取每个订单的商品。
-- 获得用户的分表信息 user_id = 66
SELECT table_flag FROM user WHERE user_id=66;
+------------+
| table_flag |
+------------+
| 9 |
+------------+
-- 获取用户订单, 这些信息值直接先返回给浏览器的
SELECT * FROM buy_order_9 WHERE user_id=66 LIMIT 0, 1;
+---------------------+---------+---------------+
| buy_order_id | user_id | user_guide_id |
+---------------------+---------+---------------+
| 3792111966815784961 | 66 | 1 |
+---------------------+---------+---------------+
-- 获取 user_guide_id=1 用户的分表信息
SELECT u.table_flag AS guide_flag
FROM user AS u, user_guide AS ug
WHERE u.user_id = ug.user_id
AND user_guide_id = 1;
+------------+
| guide_flag |
+------------+
| 2 |
+------------+
-- 浏览器通过ajax获取商品信息进行展现
SELECT *
FROM order_goods_2
WHERE sell_order_id = 3792111966815784961
AND user_guide_id = 1;
+---------------------+---------------------+---------------------+---------------+---------+------+
| order_goods_id | sell_order_id | goods_id | user_guide_id | price | num |
+---------------------+---------------------+---------------------+---------------+---------+------+
| 3792112143781859329 | 3792111966815784961 | 3792111950445416449 | 1 | 3100.00 | 2 |
| 3792112160789762049 | 3792111966815784961 | 3792111951305248769 | 1 | 5810.00 | 1 |
+---------------------+---------------------+---------------------+---------------+---------+------+
从上面的试验我们可以看到原本在 '分库分表(1)--基础表介绍' 中的关联查询就能获得出订单的数据现在需要被拆为多个部分来查询(是不可避免的, 这样做也未必不是好事)。
这里说一下我们为什么要使用ajax来获取并展现 '订单商品' 的数据:
1、我们不知道 '购买订单' 的导购的分表是哪一个,因此我们需要便利查询出的每一条 '购买订单',如果有10个订单就需要便利10次去获取对应导购是哪个分表。
2、获得分表完之后还需要通过每个分表去关联 '订单商品' 获得商品信息。
3、获得到以上信息或需要整合成一个列表返回给浏览器。
通过上面一次性把说有数据返回给浏览器的方法,会影响到用户体验,让用户觉得很慢的感觉。并且需要写复杂的逻辑,难以维护。
我们将查询时间放大,一个查是 1s 如果有10个订单 一次性完成就可能需要 11s 以上的时间才返回给浏览器。如果先将查询的订单返回给浏览器。看上去就只需要 1s就吧数据返回给浏览器了。
情况3:导购查看订单
导购也是一个普通用户, 因此一登陆系统就知道 导购ID 和 用户ID
-- 获得导购的分表信息 user_id = 6, user_guide_id = 5
SELECT table_flag FROM user WHERE user_id=6;
+------------+
| table_flag |
+------------+
| 6 |
+------------+
-- 查询订单信息
SELECT * FROM sell_order_6 WHERE user_guide_id = 5 LIMIT 0, 3;
+---------------------+---------------+---------+---------+--------+
| sell_order_id | user_guide_id | user_id | price | status |
+---------------------+---------------+---------+---------+--------+
| 3792112033412943873 | 5 | 10 | 5197.00 | 1 |
| 3792112033429721089 | 5 | 10 | 6826.00 | 1 |
| 3792112033446498305 | 5 | 10 | 5765.00 | 1 |
+---------------------+---------------+---------+---------+--------+
-- 查询订单商品信息
SELECT * FROM order_goods_6
WHERE sell_order_id IN(
3792112033412943873,
3792112033429721089,
3792112033446498305
);
+---------------------+---------------------+---------------------+---------------+---------+------+
| order_goods_id | sell_order_id | goods_id | user_guide_id | price | num |
+---------------------+---------------------+---------------------+---------------+---------+------+
| 3792112273532653569 | 3792112033412943873 | 3792111951800176641 | 5 | 7826.00 | 1 |
| 3792112292964864001 | 3792112033412943873 | 3792111952559345665 | 5 | 3057.00 | 2 |
| 3792112273545236481 | 3792112033429721089 | 3792111952660008961 | 5 | 8540.00 | 1 |
| 3792112292981641217 | 3792112033429721089 | 3792111951863091201 | 5 | 8545.00 | 1 |
| 3792112273566208001 | 3792112033446498305 | 3792111952110555137 | 5 | 8383.00 | 2 |
| 3792112292998418433 | 3792112033446498305 | 3792111952966193153 | 5 | 3282.00 | 2 |
+---------------------+---------------------+---------------------+---------------+---------+------+
情况4:导购修改订单
-- 修改订单价格
UPDATE sell_order_6 SET price = 1000.00 WHERE sell_order_id = 3792112033412943873;
情况5:店主为店铺添加商品
添加商品只有店铺的店主有权限。然而店主也是一个普通用户。
-- 获得店主的分表信息 user_id = 1
SELECT table_flag FROM user WHERE user_id=1;
+------------+
| table_flag |
+------------+
| 2 |
+------------+
-- 店主添加商品
INSERT INTO goods_2 VALUES(SnowflakeID, 商品名称, 商品价格, 门店ID);
文章出自:http://www.ttlsa.com/mysql/mysql-distributed-database-and-table-query/