手把手教你PolarDB-X中的表设计——用户表
简介: 本系列旨在描述一个具体的业务场景,给出建表的例子,帮助大家更好的使用PolarDB-X。本期的主题是:用户表。
本系列旨在描述一个具体的业务场景,给出建表的例子,帮助大家更好的使用PolarDB-X。本期的主题是:用户表。
需求描述
大多业务都会有一张用户表,用来存用户的数据,例如这样一张用户表:
user_id bigint AUTO_INCREMENT,
user_name varchar(64),
mobile_phone varchar(64),
email varchar(64),
enc_password varchar(256),
address varchar(128),
other_info1 varchar(128),
other_info2 varchar(128),
PRIMARY KEY (user_id)
)
对这张表,一般会有以下几种业务操作:
● 注册,特点是要保证用户名、手机号、邮箱等唯一:
INSERT INTO users VALUES (?, ?, ?)
● 登录,现在大多数APP都支持手机号、邮箱地址、用户名等多个维度进行登录,所以会有多种类型的SQL:
//按照用户名(user_name)进行登录:
SELECT *
FROM users
WHERE user_name = ?;
//按照手机号(mobile_phone)进行登录:
SELECT *
FROM users
WHERE mobile_phone = ?;
//按照邮箱(email)进行登录:
SELECT *
FROM users
WHERE email = ?;
● 登录后,系统内一般会使用用户ID(user_id)查询或者更新用户信息:
SELECT *
FROM users
WHERE user_id = ?;
UPDATE users
SET xxxx = ?
WHERE user_id = ?;
对于这样的一张表,我们在PolarDB-X中该如何设计呢?
这里我们根据数据库的MODE(PolarDB-X中数据库的MODE参数:https://help.aliyun.com/document_detail/416411.html),给出两种示例:
DRDS模式
在DRDS模式的数据库中,我们需要设计表的分区键。
users表的查询条件有user_id、user_name、mobile_phone、email,这四种条件的查询的量都差不多,都属于在线类查询。对于传统的分库分表中间件来说,一个表的分区键只能选择一个,那么无论选择哪一个做分区键,对于其他三个条件的查询,都会是一场灾难。
PolarDB-X支持全局索引(什么是全局索引:https://zhuanlan.zhihu.com/p/395415647),那这个问题就很好解决了,我们按照下面语句建表即可:
CREATE DATABASE drds_test MODE='drds';
use drds_test;
CREATE TABLE users (
user_id bigint AUTO_INCREMENT,
user_name varchar(64),
mobile_phone varchar(64),
email varchar(64),
enc_password varchar(256),
address varchar(128),
other_info1 varchar(128),
other_info2 varchar(128),
PRIMARY KEY (user_id)
) DBPARTITION BY HASH(user_id);
CREATE GLOBAL UNIQUE INDEX gsi_users_user_name ON users (user_name) DBPARTITION BY HASH(user_name);
CREATE GLOBAL UNIQUE INDEX gsi_users_mobile_phone ON users (mobile_phone) DBPARTITION BY HASH(mobile_phone);
CREATE GLOBAL UNIQUE INDEX gsi_users_email ON users (email) DBPARTITION BY HASH(email);
这样,我们在user_name、mobile_phone、email上分别创建了三个全局唯一索引。对于上述的查询SQL,每一种都会非常的高效。同时,也会保证注册场景下的唯一性。
当然,这些创建索引的语句也可以直接合并在建表语句中,相关语法参考:https://help.aliyun.com/document_detail/316584.html:
DROP TABLE users;
CREATE TABLE users (
user_id bigint AUTO_INCREMENT,
user_name varchar(64),
mobile_phone varchar(64),
email varchar(64),
enc_password varchar(256),
address varchar(128),
other_info1 varchar(128),
other_info2 varchar(128),
PRIMARY KEY (user_id),
UNIQUE GLOBAL KEY gsi_users_email (email) DBPARTITION BY HASH(email),
UNIQUE GLOBAL KEY gsi_users_mobile_phone (mobile_phone) DBPARTITION BY HASH(mobile_phone),
UNIQUE GLOBAL KEY gsi_users_user_name (user_name) DBPARTITION BY HASH(user_name)
) DBPARTITION BY hash(user_id);
此外,如果想进一步提升查询的性能,避免全局索引回表的代价,还可以把全局索引创建为全局聚簇索引。这样会消耗更多的空间,但查询性能会更高。例如:
CREATE GLOBAL CLUSTERED UNIQUE INDEX gsi_clustered_users_user_name ON users (user_name) DBPARTITION BY HASH(user_name);
注意:上述用法对于PolarDB-X 1.0(version >= 5.4.12)也同样适用。
AUTO模式
对于AUTO模式,则无需关注分区键等信息,像在MySQL中建表即可:
CREATE DATABASE auto_test MODE='auto';
use auto_test;
CREATE TABLE users(
user_id bigint auto_increment,
user_name varchar(64),
mobile_phone varchar(64),
email varchar(64),
enc_password varchar(256),
address varchar(128),
other_info1 varchar(128),
other_info2 varchar(128),
PRIMARY KEY(user_id),
UNIQUE KEY uk_user_name(user_name),
UNIQUE KEY uk_mobile_phone(mobile_phone),
UNIQUE KEY uk_email(email)
);
同样的能达到和手动分区一样的效果。
我们可以使用EXPLAIN语句来查看一下执行计划:
EXPLAIN SELECT * FROM users WHERE mobile_phone = 1;
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| LOGICAL EXECUTIONPLAN |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Project(user_id="user_id", user_name="user_name", mobile_phone="mobile_phone", email="email", enc_password="enc_password", address="address", other_info1="other_info1", other_info2="other_info2") |
| BKAJoin(condition="user_id = user_id", type="inner") |
| IndexScan(tables="uk_mobile_phone_$1ace[p16]", sql="SELECT `user_id`, `mobile_phone` FROM `uk_mobile_phone_$1ace` AS `uk_mobile_phone_$1ace` WHERE (`mobile_phone` = ?)") |
| Gather(concurrent=true) |
| LogicalView(tables="users[p1,p2,p3,...p16]", shardCount=16, sql="SELECT `user_id`, `user_name`, `email`, `enc_password`, `address`, `other_info1`, `other_info2` FROM `users` AS `users` WHERE ((`mobile_phone` = ?) AND (`user_id` IN (...)))") |
| HitCache:false |
| Source:PLAN_CACHE |
| TemplateId: beaaba3a |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
8 rows in set (0.32 sec)
可以看到,这个SQL会正确的使用索引来进行查询,而不会进行全表扫描。
测试环境
以上示例均在阿里云公共云PolarDB-X 2.0 5.4.13-16462728验证通过。
本文作者:梦实
本文来源:PolarDB-X 知乎号
手把手教你PolarDB-X中的表设计——用户表的更多相关文章
- 手把手教你写Sublime中的Snippet
手把手教你写Sublime中的Snippet Sublime Text号称最性感的编辑器, 并且越来越多人使用, 美观, 高效 关于如何使用Sublime text可以参考我的另一篇文章, 相信你会喜 ...
- orale数据库.实例.表空间.用户.表
近期因为工作原因接触到Oracle数据库.了解到Oracle和mysql的结构上还是有很大的区别的. Oracle数据库---实例---表空间---用户---表 我们将从这5个方面来了解Oracle ...
- 第三百七十三节,Django+Xadmin打造上线标准的在线教育平台—创建用户app,在models.py文件生成3张表,用户表、验证码表、轮播图表
第三百七十三节,Django+Xadmin打造上线标准的在线教育平台—创建用户app,在models.py文件生成3张表,用户表.验证码表.轮播图表 创建Django项目 项目 settings.py ...
- Oracle中查看所有的表,用户表,列名,主键,外键
在Oracle中查看所有的表: select * from tab/dba_tables/dba_objects/cat; 看用户建立的表 : select table_name from user_ ...
- SQL Server 中获取所有的用户表、用户视图的信息
直接贴代码了: 用户表: SELECT s.Name,Convert(varchar(max),tbp.value) as Description FROM sysobjects s AND (tbp ...
- mysql设计与优化以及数据库表设计与表开发规范
一.设计问题? 1.主键是用自增还是UUID ? Innodb 中的主键是聚簇索引. 如果主键是自增的,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,当一页写满,就会自动开辟一个新的 ...
- oracle习题练习-表空间-用户-表-约束
题一 1. 创建名字为hy_tablespace的表空间,默认大小为10M;@@ 2. 创建一个用户,用户名以自己名字命名,并指定命名空间为hy_tablespace;@@@@ ...
- MySQL进阶:约束,多表设计,多表查询,视图,数据库备份与还原
MySQL进阶 知识点梳理 一.约束 1. 外键约束 为什么要有外键约束 例如:一个user表,一个orderlist 如果现在想要直接删除id为1的张三,但是orderlist里还有用户id为1的订 ...
- 手把手教你在VirtualBox中与主机共享文件夹
安装VirtualBox为了共享文件夹,折腾了一晚上!网上的很多资料都不是很全面,这里就全面的总结一下,如果有其他的疑问,可以留言多多交流. VirtualBox下载地址,版本为5.1.2 设置共享文 ...
- 小姐姐手把手教你JS数组中的对象去重
有时候数据库中的数据重复的,我们另一个需求需要数据的唯一性 那么这时候就用到这个方法了 我还是以截图的方式发粗来 不然太丑了 见谅 console.log(map)打印出来的结果已经帮我们把需要的 ...
随机推荐
- 一个简单的HTTP服务器的实现
我们继续我们的HTTP服务器的实现(使用别的代码来实现), 这个HTTP服务器的实现,我们主要就是关注TCP服务器中的recv还有send的处理. 首先,看一下HTTP,我们在用浏览器访问我们的TCP ...
- FAT32 文件系统详解
PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明 本文作为本人csdn blog的主站的备份.(Bl ...
- vue基础知识和原理(一)
1. vue基础知识和原理 1.1 初识Vue 想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象 demo容器里的代码依然符合html规范,只不过混入了一些特殊的Vue语法 demo容器 ...
- CSS(相对定位relative、绝对定位absolute、固定定位fixed、定位应用、元素的显示和隐藏)
一. 定位(position) 介绍 1.1 为什么使用定位 我们先来看一个效果,同时思考一下用标准流或浮动能否实现类似的效果? 场景1: 某个元素可以自由的在一个盒子内移动位置,并且压住其他盒子. ...
- 记录--h5调用手机摄像头踩坑
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 1. 背景 一般业务也很少接触摄像头,有也是现成的工具库扫个二维码.难得用一次,记录下踩坑. 2.调用摄像头的方法 2.1. input ...
- FFmpeg开发笔记(四)FFmpeg的动态链接库介绍
FFmpeg不仅提供了ffmpeg.ffplay和ffprobe三个可执行程序,还提供了八个工具库,使得开发者能够调用库里面的函数,从而实现更精准的定制化开发需求.这八个库的名字是avcodec.av ...
- Unable to load library ‘xxx‘: 找不到指定的模块。找不到指定的模块。 Can‘t obtain InputStream for win32-x86-64/xxx.dll
我使用的是 <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</a ...
- Springboot访问html页面
项目结构如图 1.html页面创建 在原有的项目resouces目录下创建static包,并在static下创建pages,然后在pages包下index.html. index.html内容 < ...
- exist和left join 性能对比
今天遇到一个性能问题,再调优过程中发现耗时最久的计划是exist 部分涉及的三个表. 然后计划用left join 来替换exist,然后查询了很多资料,大部分都说exist和left join 性能 ...
- 【Java】try {}里有一个 return 语句,那么紧跟在这个 try 后的 finally {}里的 code 会不会被执行,什么时候被执行,在 return 前还是后?
try {}里有一个 return 语句,那么紧跟在这个 try 后的 finally {}里的 code 会不会被执行,什么时候被执行,在 return 前还是后? package com.test ...