MySQL订单分库分表多维度查询
MySQL分库分表,一般只能按照一个维度进行查询.
按照用户的维度查询很快,因为最终的查询落在一台服务器上.
但是如果按照商户的维度查询,则代价非常高.
需要查询全部64台服务器.
在分页的情况下,更加恶化.
比如某个商户查询第10页的数据(按照订单的创建时间).需要在每台数据库服务器上查询前100条数据,程序收到 64*100 条数据,然后按照订单的创建时间排序,截取排名90-100号的10条记录返回,然后抛弃其余的6390条记录.如果查询的是第100页,第1000页,则对数据库IO,网络,中间件CPU,都是不小的压力.
分库分表之后,为了应对多维度查询,很多情况下会引入冗余.
比如两个集群,一个按照用户ID分库分表,另外一个按照商户ID分库分表.
这样多维度查询的时候,各查各的.
但是有几个问题,一样不好解决.
比如,
每扩展一个维度,就需要引入一个集群.
集群间的数据,如何保证一致性.
冗余占用大量磁盘空间.
从朋友那里看到的订单表结构.做冗余会占用大量的磁盘空间.
create table TS_ORDER
(
ORDER_ID NUMBER(8) not null,
SN VARCHAR2(50),
MEMBER_ID NUMBER(8),
STATUS NUMBER(2),
PAY_STATUS NUMBER(2),
SHIP_STATUS NUMBER(2),
SHIPPING_ID NUMBER(8),
SHIPPING_TYPE VARCHAR2(255),
SHIPPING_AREA VARCHAR2(255),
PAYMENT_ID NUMBER(8),
PAYMENT_NAME VARCHAR2(50),
PAYMENT_TYPE VARCHAR2(50),
PAYMONEY NUMBER(20,2),
CREATE_TIME NUMBER(20) not null,
SHIP_NAME VARCHAR2(255),
SHIP_ADDR VARCHAR2(255),
SHIP_ZIP VARCHAR2(20),
SHIP_EMAIL VARCHAR2(50),
SHIP_MOBILE VARCHAR2(50),
SHIP_TEL VARCHAR2(50),
SHIP_DAY VARCHAR2(255),
SHIP_TIME VARCHAR2(255),
IS_PROTECT VARCHAR2(1),
PROTECT_PRICE NUMBER(20,2),
GOODS_AMOUNT NUMBER(20,2),
SHIPPING_AMOUNT NUMBER(20,2),
ORDER_AMOUNT NUMBER(20,2),
WEIGHT NUMBER(20,2),
GOODS_NUM NUMBER(8),
GAINEDPOINT NUMBER(11) default 0,
CONSUMEPOINT NUMBER(11) default 0,
DISABLED VARCHAR2(1),
DISCOUNT NUMBER(20,2),
IMPORTED NUMBER(2) default 0,
PIMPORTED NUMBER(2) default 0,
COMPLETE_TIME NUMBER(11) default 0,
CANCEL_REASON VARCHAR2(255),
SIGNING_TIME NUMBER(11),
THE_SIGN VARCHAR2(255),
ALLOCATION_TIME NUMBER(11),
SHIP_PROVINCEID NUMBER(11),
SHIP_CITYID NUMBER(11),
SHIP_REGIONID NUMBER(11),
SALE_CMPL NUMBER(2),
SALE_CMPL_TIME NUMBER(11),
DEPOTID NUMBER(11),
ADMIN_REMARK VARCHAR2(1000),
COMPANY_CODE VARCHAR2(32),
PARENT_SN VARCHAR2(50),
REMARK VARCHAR2(100),
GOODS CLOB,
ORIGINAL_AMOUNT NUMBER(20,2),
IS_ONLINE CHAR(1),
IS_COMMENTED CHAR(1) default 0,
ORDER_FLAG CHAR(1) default 1
)
可以试试用表代替索引的方法.
1.分库分表
2.最终一致性
3.用表代替索引的功能

首先,还是基于分库分表.订单表按照用户ID mod 64 分到不同的服务器上(按照查询最多的维度分)。
数据库服务器1 的数据库名称为 db_1
数据库服务器2 的数据库名称为 db_2
...
以db_1为例,创建如下表
1.订单表
TS_ORDER_1 分区表,每个月一个分区.
2.事务表
create table tran_log_1(
tran_id bigint primary key,
param varchar(2000)
);
分区表,每个月一个分区.
3.消息表
create table msg_log_1(
tran_id bigint,
shardKey varchar(20) not null,
primary key(tran_id,shardKey)
);
分区表,每个月一个分区.
4.维度索引表
create table shard_shop_1(
id bigint primary key auto_increment,
shopid int,
ts timestamp,
state int,
dbid int,
orderid bigint,
index(shopid,ts,state)
);
分区表,每个月一个分区.
关于使用事务表,消息表实现分库分表最终一致性请参考
http://blog.itpub.net/29254281/viewspace-1819422/
关于集群主键生成服务请参考
http://blog.itpub.net/29254281/viewspace-1811711/
订单创建的流程
Web服务器接收到用户订单,首先通过RPC获取一个事务ID(tran_id).
用事务ID mod 64 找到数据库服务器,
将事务ID,参数写入tran_log 表,
然后将事务ID,参数写入消息队列.
如果写入消息队列成功,则提交事务.否则回滚事务.
此时就可以返回用户界面.
后端处理服务收到消息队列的信息,首先查询tran_log 表,是否存在这个事务ID,如果不存在则不予处理.
然后将队列的消息,分为两个维度分别处理,一个是用户维度,一个是商户维度.
作为用户维度,
先根据用户ID mod 64 找到最终落地的数据库,查询那个数据库的消息表msg_log,在用户维度,是否存在这个事务ID,如果存在,则不予处理.
(select count(*) from msg_log_XX where shardKey='订单创建:用户维度' and tran_id=?)
如果不存在,则开启一个事务
插入订单表,我觉得可以用tran_id直接作为订单的ID,
并且插入消息表 insert msg_log_XX(tran_id,shardKey) values(?,'订单创建:用户维度');
提交事务,commit.
作为商户维度,
则根据商户ID mod 64 找到最终的数据库,和用户维度的数据库,可能不是同一台服务器.
同样,也是先查询落地数据库的消息表,
(select count(*) from msg_log_XXX where shardKey='订单创建:商户维度' and tran_id=?)
如果不存在记录,则开启事务,
插入维度索引表,
insert into shard_shop_XXX(shopid,ts,state,dbid,orderid) values(......)
shopid,ts,state 商户ID,订单时间,订单状态都是根据订单的原始信息.
dbid 指的是 根据用户维度(主维度),订单数据所在的数据库ID,
orderid 指的是 在用户维度(主维度),订单表的主键.
插入消息表,insert msg_log_XX(tran_id,shardKey) values(?,'订单创建:商户维度');
最后提交.
这样,作为商户维度查询的时候,先根据商户的ID mod 64 找到 维度索引表,获取该商户的订单信息
select * from shard_shop_1 where shopid=? and state=2 order by ts limit 300,10;
获取的信息可能如下
可以看到,符合条件的订单信息,分别来自 服务器1,2,16,32,64
获取了这部分信息,就可以直接去这些服务器上取数据,并且是主键查询,速度很快.
每隔一段时间,由后台程序,查看 tran_log和msg_log,如果发现有缺失的数据,则进行事务补偿.
扩展的时候,则新增维度索引表即可.
因为所有的表,都是按月的分区表,可以将过去的冷数据,在一个服务器集中存放,这个实例就同时存放64个数据库.毕竟都是冷数据,访问量很小.
能分还要能合.比如:
MySQL订单分库分表多维度查询的更多相关文章
- MySQL+MyCat分库分表 读写分离配置
一. MySQL+MyCat分库分表 1 MyCat简介 java编写的数据库中间件 Mycat运行环境需要JDK. Mycat是中间件.运行在代码应用和MySQL数据库之间的应用. 前身 : cor ...
- MySQL之分库分表
MySQL之分库分表(MyCAT实现) 分库分表介绍 随着微服务这种架构的兴起,我们应用从一个完整的大的应用,切分为很多可以独立提供服务的小应用.每个应用都有独立的数据库. 数据的切分分为两种: ...
- 使用ShardingSphere-JDBC完成Mysql的分库分表和读写分离
1. 概述 老话说的好:选择比努力更重要,如果选错了道路,就很难成功. 言归正传,之前我们聊了使用 MyCat 实现Mysql的分库分表和读写分离,MyCat是服务端的代理,使用MyCat的好处显而易 ...
- php面试专题---mysql数据库分库分表
php面试专题---mysql数据库分库分表 一.总结 一句话总结: 通过数据切分技术将一个大的MySQLServer切分成多个小的MySQLServer,既攻克了写入性能瓶颈问题,同一时候也再一次提 ...
- mysql数据库分库分表shardingjdbc
分库分表理解 分库分表应用于互联网的两个场景;大量数据和高并发,通常策略有两种:垂直分库,水平拆分 垂直拆分:是根据业务将一个库拆分为多个库,将一个表拆分为多个表,例如:将不常用的字段和经常访问的字段 ...
- 一致性hash 大众点评订单分库分表实践
井底之蛙 https://mp.weixin.qq.com/s?src=3×tamp=1543228894&ver=1&signature=uF6nV0yYseJ55 ...
- 面试官:说说Mysql数据库分库分表,并且会有哪些问题?
之前一篇文章已经谈到了数据库集群之主从集群也就是读写分离,也提到了读写分离其实只是分担了访问的压力,但是存储的压力没有解决. 存储的压力说白了就是随着系统的演化,需求的增加,可能表的数量会逐渐增多,比 ...
- SpringBoot+MybatisPlus+Mysql+Sharding-JDBC分库分表实践
一.序言 在实际业务中,单表数据增长较快,很容易达到数据瓶颈,比如单表百万级别数据量.当数据量继续增长时,数据的查询性能即使有索引的帮助下也不尽如意,这时可以引入数据分库分表技术. 本文将基于Spri ...
- Mysql 之分库分表方案
Mysql分库分表方案 为什么要分表 当一张表的数据达到几千万时,你查询一次所花的时间会变多,如果有联合查询的话,我想有可能会死在那儿了.分表的目的就在于此,减小数据库的负担,缩短查询时间. mysq ...
随机推荐
- Django用户认证系统(二)Web请求中的认证
在每个Web请求中都提供一个 request.user 属性来表示当前用户.如果当前用户未登录,则该属性为AnonymousUser的一个实例,反之,则是一个User实例. 你可以通过is_authe ...
- SSH 远程连接
ssh远程连接 准备工作: 1 准备两台linux pc 我们一般用的是VMware虚礼软件 2 这两台linux可以互通 3 linux1 :192.168.2.2 这台为你要连接的服务器 linu ...
- FPGA中latency与delay概念的区别
2013-06-17 21:09:26 最近学习流水线以及状态机,总遇到注入加入寄存器可以分割组合逻辑,从而提高电路的运行频率的说法:还有流水线可以提高速度的说法,刚开始很是疑惑,觉得流水线的方法,输 ...
- 【HDOJ】4043 FXTZ II
1. 题目描述有n个球,第i个球的伤害值为$2^i-1, i \in [1,n]$.有甲乙两个人,每次由甲选择n个球中的一个,用它以相同概率攻击自己或者乙,同时彻底消耗这个球.这样的攻击最多进行n次. ...
- Android-xUtils框架介绍(二)
昨天对xUtils整体上做了一个简单的介绍,今天咱们就代码码起,真刀实枪的也看看,看看如何快速便捷的把xUtils给集成到大家的项目中去.xUtils中有四大组件可以供我们使用,分别是ViewUtil ...
- Java面试题-并发工具
1. 如何实现一个流控程序,用于控制请求的调用次数?
- codevs3731 寻找道路
方向dfs判定是否可行,spfa跑最短路. noip水题,wa好几次. #include<cstdio> #include<algorithm> #include<cst ...
- 使用Amoeba 实现MySQL DB 读写分离
Amoeba(变形虫)项目是一个开源框架,于2008年开始发布一款 Amoeba for Mysql软件: 这个软件致力于MySQL的分布式数据库前端代理层,它主要在应用层访问MySQL的时候充当SQ ...
- 手动启动angular
关于手动启动 angular 的问题 angular核心原理解析1:angular自启动过程 angular.element(document).ready(function() { angular. ...
- jquery适用技巧
jQuery对象与dom对象的转换 只有jquery对象才能使用jquery定义的方法.注意dom对象和jquery对象是有区别的,调用方法时要注意操作的是dom对象还是jquery对象. 普通的do ...