地址:联系地址联系地址联系地址
电话:020-123456789
传真:020-123456789
邮箱:admin@aa.com
对主键来说 ,分库分表要保证在所有分片中都唯一,索引设计设计实践它本质上就是索局索一个全局唯一的索引 。如果用大部分同学喜欢的引全引自增作为主键,就会发现存在很大的最佳问题 。
因为自增并不能在插入前就获得值,分库分表而是索引设计设计实践要通过填 NULL 值,然后再通过函数 last_insert_id()获得自增的索局索值。所以,引全引如果在每个分片上通过自增去实现主键,最佳可能会出现同样的分库分表自增值存在于不同的分片上 。
比如 ,索引设计设计实践对于电商的索局索订单表 orders,其表结构如下(分片键是引全引o_custkey ,表的最佳主键是o_orderkey) :
CREATE TABLE `orders` (n `O_ORDERKEY` int NOT NULL auto_increment,n `O_CUSTKEY` int NOT NULL,n `O_ORDERSTATUS` char(1) NOT NULL,n `O_TOTALPRICE` decimal(15,2) NOT NULL,n `O_ORDERDATE` date NOT NULL,n `O_ORDERPRIORITY` char(15) NOT NULL,n `O_CLERK` char(15) NOT NULL,n `O_SHIPPRIORITY` int NOT NULL,n `O_COMMENT` varchar(79) NOT NULL,n PRIMARY KEY (`O_ORDERKEY`),n KEY (`O_CUSTKEY`)n ......n) ENGINE=InnoDBn
如果把 o_orderkey 设计成上图所示的自增 ,那么很可能 o_orderkey 同为 1 的记录在不同的分片出现,如下图所示:
所以 ,在分布式数据库架构下,尽量不要用自增作为表的主键:自增性能很差 、安全性不高、不适用于分布式架构 。
讲到这儿 ,我们已经说明白了“自增主键”的所有问题,那么该如何设计主键呢?依然还是用全局唯一的键作为主键,比如 MySQL 自动生成的有序 UUID;业务生成的全局唯一键(比如发号器);或者是开源的 UUID 生成算法,比如雪花算法(但是存在时间回溯的问题) 。
总之,用有序的全局唯一替代自增 ,是这个时代数据库主键的主流设计标准,如果你还停留在用自增做主键,或许代表你已经落后于时代发展了。
通过分片键可以把 SQL 查询路由到指定的分片,但是在现实的生产环境中 ,业务还要通过其他的索引访问表 。
还是以前面的表 orders 为例 ,如果业务还要根据 o_orderkey 字段进行查询,比如查询订单 ID 为 1 的订单详情:
SELECT * FROM orders WHERE o_orderkey = 1n
我们可以看到 ,由于分片规则不是分片键,所以需要查询 4 个分片才能得到最终的结果,如果下面有 1000 个分片 ,那么就需要执行 1000 次这样的 SQL ,这时性能就比较差了 。
但是 ,我们知道 o_orderkey 是主键,应该只有一条返回记录 ,也就是说,o_orderkey 只存在于一个分片中 。这时,可以有以下两种设计 :
这两种设计的本质都是通过冗余实现空间换时间的效果,否则就需要扫描所有的分片 ,当分片数据非常多 ,效率就会变得极差。
而第一种做法通过对表进行冗余 ,对于 o_orderkey 的查询,只需要在 o_orderkey = 1的分片中直接查询就行 ,效率最高 ,但是设计的缺点又在于冗余数据量太大 。
所以 ,改进的做法之一是实现一个索引表