mysql 拆分表,怎么查询?

mysql 内容表数据超过3千万行太大了,我按1千万一个表拆成3个表,那么每次查询的时候,都要同时查询3个表吗?如果以后有2亿数据,岂不是每次要查询20个表?怎么解决数据量大表拆分后的查询?

大表分表后每个表的结构相同,可以用sql的union。比如a,b表结构相同可以通过union来联接
select * from a
union all
select * from b
where ...
一、Union和Union All到底有什么区别
  Union:对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序;

  Union All:对两个结果集进行并集操作,包括重复行,不进行排序;

  比如一家公司在中美均有雇员,我们使用Union这个命令想查出中美所有雇员,是不行的。假如我们有两个名字相同的雇员,他们当中就只会有一个人被列出来了。UNION 命令只会选取不同的值。而Union All则可以查出全部的值。

  详细了解:https://www.w3school.com.cn/sql/sql_union.asp

二、大表拆分后的查询效率问题
  假如一个超级大的用户表按照数据拆分成10个表后,某个用户登录的时候是不是要从10个表里面去查询这个用户的用户名和密码是否正确。这样就存在效率问题。

  一种方案就是拆表的时候,按照一定规则来拆表,查询的时候按照这个规则来查,通过规则就能知道到底该去哪个表查,如果胡乱拆表,那一个表和10个表有什么区别。

三、大表拆分
  表的拆分分为横向拆分(记录的拆分)和纵向拆分(字段的拆分)。拆分表的目的:提高查询速度。

(1)横向拆分 - 记录的拆分

  我们从一个案例去解释,情景是这样的:某某博客,有50W的博客量,有2w的用户,发现随着用户和博客数的增加,查询速度日渐下降,现在要对博客表blog与用户表user进行优化。

  表结构如下:
create table blog(
bid
title
content
pubtime
uid
) 50万
create table user(
uid
username
password
nick
......
) 2万
首先我们要决定根据哪个字段对记录进行拆分,查询决定了拆分,在这里我们根据uid字段对两个表进行拆分是比较合理的。

博客表根据uid去拆分:
1-5000------blog_1
5001-10000-----blog_2
10001-15000----blog_3
15001-20000----blog_4
人员表根据uid 等分:
1-5000------user_1
5001-10000-----user_2
10001-15000----user_3
15001-20000----user_4

  比如查询某人的博客:

// 根据uid确认表名:
$num=ceil(12345/5000);
select uid,bid,title,pubtime from blog_$num where uid=12345;
(2)纵向拆分:字段的拆分 - 把活跃字段(常用)、惰性字段(不常用)分开。

  案例:比如人员表,活跃字段像用户名、密码、昵称等,惰性字段像手机号、邮箱、性别等不经常使用和修改的字段。

  一张完整的用户表可以拆分为两张表,如下:

create table user(
uid int key auto_increment,
username char(20),
password char(32) not null,
nick char(10)
);
create table user_ext(
uid
regtime
name
email
qq
phone
sex
)

方案一:
使用sharding-jdbc进行分库分表,查询时系统会自动帮你进行操作,不用额外指明具体查询哪个表
方案二:
根据业务进行拆分,读写操作时进行精确匹配,比如需要拆分5个表(user1、user2、user3、user4、user5),然后写数据时将用户id末尾为0、5的写进user1,id末尾为1,6的写进user2,以此类推,读数据时根据用户id进行指定表查询。

  1. 建议尝试使用分区表的方式来替代拆分的实体表,这样使用指定条件的时候会自动指向分区,而不用全表扫。
  2. 拆分的时候,尽量按照业务定义来拆,比如与时间有关的,前端查询条件假设不会超过一个月,那么拆的时候就一个月拆一次。
  3. 结合应用代码逻辑,根据前端输入的查询条件,动态指向不同的拆分表。
  4. 当mysql的分区表和应用代码逻辑无法满足的时候,就表示该做大数据相关方面的建设了,比如建个数仓,并设计好相关数据统计模型

拆表按一定规则进行拆分 ,比如根据搜索值进行确定拆分到具体某一张表,这样根据提供的搜索值就可以直接确定是哪一张表,就不用全部表查了

拆分表要按照业务来拆, 而不是数据量, 比如 时间/城市 这种的单次查的;
还有你可以借助es, es支持多索引查询, 实现就是将查询字段及主键id同步到es, 然后用es进行筛选项拿到主键id再进mysql进行获取详细内容;

大数据量查询解决方案:

  1. 一些列表查询操作可以将少量显示字段数据同步到es,使用es的搜索功能支撑分页查询,某条数据的详细查询根据分库分表的策略直接定位到某个库或表
  2. 历史数据可以做冷备份处理,数据库中只保留指定时间(一年)内的热数据,例如支持宝等app的很多功能只支持查询一年内的数据

数据量增大后不建议按条件/数量来拆分表来各自存放部分数据,同一个业务的数据拆分在不同的表中这样不是较好的方案,且维护极不方便。
注:如果不是走投无路,尽量不要分库分表。
本人之前自己有过数十亿表的操作经验,以此应该可以轻松回答你的疑问。如果题主有不解的地方欢迎提问。
最佳实施建议:
1,考虑数据是否后续会有删除?是否全量数据都要长期使用?
如果不是长期使用,通过定期事件来清理指定过期数据来减少存放记录数,方法1:定期脚本/系统清理数据。 方法2:db中创建事件定时清理。并做到定期对db进行维护释放空间提升性能。
2,如果是部分数据要长期备份,则通过其它系统(自建的转移程序等)将部分数据定期提取到其它持久化存储或存储组件中,这样较好,而不是全部存放在关系型数据库中,按实际情况来,该方法思路就是区别不同业务进行多来源查询。
3,如果就是要长期使用此类数据库表存放该数据,且数据增长量较快,则使用表分区方式,基于事件+存储过程完成,这样的效果就是定期按指定的规则将数据规划到不同的逻辑分区中,既能提升查询、删除效率,也能优化存储空间(普通的定期删除数据不能释放空间)

哈希表你知道吧,用一个算法查询到它在哪个表。

可以创建视图,即创建虚拟的表,然后进行查询,原有的表不需要进行改动,也可以随时修改视图条件进行控制表的大小和内容

拆分表的时候要根据业务情况以合理的方式拆分,尽量使拆分以后的实时交易逻辑每次只操作一张表,离线分析报表或离线批处理等可以对多张表进行操作

拆分表查询时,你必须指定默认查询条件查询单张表的数据才行,不然你拆分表就没有意义啊
比如银行流水记录表是年表拆分,查询条件中设置不允许跨年查询

可以借助es、redis