数据库分表后怎么查询 mysql分库后怎么查询
大家好,今天来为大家分享数据库分表后怎么查询的一些知识点,和mysql分库后怎么查询的问题解析,大家要是都明白,那么可以忽略,如果不太清楚的话可以看看本篇文章,相信很大概率可以解决您的问题,接下来我们就一起来看看吧!
mysql怎么分表
当一张的数据达到几百万时,你查询一次所花的时间会变多,如果有联合查询的话,我想有可能会死在那儿了。分表的目的就在于此,减小数据库的负担,缩短查询时间。
分表
1,做mysql集群。例如:利用mysql cluster,mysql proxy,mysql replication,drdb等等
有人会问mysql集群,和分表有什么关系吗?虽然它不是实际意义上的分表,但是它起到了分表的作用。做集群的意义是什么呢?为一个数据库减轻负担,说白了就是减少sql排队队列中的sql的数量。
举个例子:有10个sql请求,如果放在一个数据库服务器的排队队列中,他要等很长时间,如果把这10个sql请求,分配到5个数据库服务器的排队队列中,一个数据库服务器的队列中只有2个,这样等待时间是不是大大的缩短了呢?这已经很明显了。
优点:扩展性好,没有多个分表后的复杂操作(php代码)
缺点:单个表的数据量还是没有变,一次操作所花的时间还是那么多,硬件开销大。
2,预先估计会出现大数据量并且访问频繁的表,将其分为若干个表
这种预估大差不差的,论坛里面发表帖子的表,时间长了这张表肯定很大,几十万,几百万都有可能。聊天室里面信息表,几十个人在一起一聊一个晚上,时间长了,这张表的数据肯定很大。像这样的情况很多。所以这种能预估出来的大数据量表,我们就事先分出个N个表,这个N是多少,根据实际情况而定。
优点:避免一张表出现几百万条数据,缩短了一条sql的执行时间
缺点:当一种规则确定时,打破这条规则会很麻烦,上面的例子中我用的hash算法是crc32,如果我现在不想用这个算法了,改用md5后,会使同一个用户的消息被存储到不同的表中,这样数据乱套了。扩展性很差。
3,利用merge存储引擎来实现分表
我觉得这种方法比较适合,那些没有事先考虑,而已经出现了的,数据查询慢的情况。这个时候如果要把已有的大数据量表分开比较痛苦,最痛苦的事就是改代码,因为程序里面的sql语句已经写好了。现在一张表要分成几十张表,甚至上百张表,这样sql语句是不是要重写呢?举个例子,我很喜欢举子
mysql>show engines;的时候你会发现mrg_myisam其实就是merge。
mysql> CREATE TABLE IF NOT EXISTS `user1`(
-> `id` int(11) NOT NULL AUTO_INCREMENT,
-> `name` varchar(50) DEFAULT NULL,
-> `sex` int(1) NOT NULL DEFAULT'0',
-> PRIMARY KEY(`id`)
->) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
Query OK, 0 rows affected(0.05 sec)
mysql> CREATE TABLE IF NOT EXISTS `user2`(
-> `id` int(11) NOT NULL AUTO_INCREMENT,
-> `name` varchar(50) DEFAULT NULL,
-> `sex` int(1) NOT NULL DEFAULT'0',
-> PRIMARY KEY(`id`)
->) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
Query OK, 0 rows affected(0.01 sec)
mysql> INSERT INTO `user1`(`name`, `sex`) VALUES('张映', 0);
Query OK, 1 row affected(0.00 sec)
mysql> INSERT INTO `user2`(`name`, `sex`) VALUES('tank', 1);
Query OK, 1 row affected(0.00 sec)
mysql> CREATE TABLE IF NOT EXISTS `alluser`(
-> `id` int(11) NOT NULL AUTO_INCREMENT,
-> `name` varchar(50) DEFAULT NULL,
-> `sex` int(1) NOT NULL DEFAULT'0',
-> INDEX(id)
->) TYPE=MERGE UNION=(user1,user2) INSERT_METHOD=LAST AUTO_INCREMENT=1;
Query OK, 0 rows affected, 1 warning(0.00 sec)
mysql> select id,name,sex from alluser;
+----+--------+-----+
| id| name| sex|
+----+--------+-----+
| 1|张映| 0|
| 1| tank| 1|
+----+--------+-----+
2 rows in set(0.00 sec)
mysql> INSERT INTO `alluser`(`name`, `sex`) VALUES('tank2', 0);
Query OK, 1 row affected(0.00 sec)
mysql> select id,name,sex from user2
->;
+----+-------+-----+
| id| name| sex|
+----+-------+-----+
| 1| tank| 1|
| 2| tank2| 0|
+----+-------+-----+
2 rows in set(0.00 sec)优点:扩展性好,并且程序代码改动的不是很大
缺点:这种方法的效果比第二种要差一点
sql 大量数据分表查询
你这种方式可以实现,但查询会变得很复杂,而且很多存储过程可以都不能用了。
另一种方式就是纵向分开A表。
就是说把A表分为AA和AB两个表。依据就是AA里面是小的,经常被查询用到的列,比如日期,ID。AB里面是大的,不经常查询的列比如text,xml,file等。AA和AB通过外键联系。这样你的查询就不用跨很多分区,结果会快很多。
还有一个办法是把所有用到的列一起建一个索引,肯定会加快查询,但这种方式会增加很多硬盘开销,同时降低插入和更改的效率。
一句题外话:
数据库管理中最好不要轻易做这么大的改动。这个查询可能很慢,但如果用户不是经常查或者已经习惯了,不如不改。
mysql分库后怎么查询
分库分表的策略,依项目需求而定,这里采用的是常规的做法:根据取模的方式,假设我们水平分库2个,每个库又水平拆表2个既总共有4个表,查询的时候默认没有按照其他的条件进行排序,假设我们要查询第41页的数据,每页显示10条数据
第一种:
也是最简单的一种:通过额外的添加一张关联表,属性中必有id属性,至于是否有库id属性和表id属性(既第几个库和第几个表)可有可无,因为这个可以根据id自行取模获取,注意这张表存放的数据是所有数据,但是胜在属性列少,只有提供索引的几个属性列,这样的话我们只需要select* from brand_temp where? limit 400,10(插叙第41页的数据,每页显示5条数据),然后我们获取了id之后就可以去对应的表中查询了
第二种:
最耗费性能的一种,如果我们要查询第一页的记录,单库单表的sql为:select* from db limit 0,10;当我们分库分片之后语句还是同样的语句,但是这时候我们需要对4个表返回的记录在内存中进行解析,然后通过id进行升序,取得前10条数据返回?数据量小,页码小的时候很ok,但是如果我们要查询第2页的数据的时候,sql单体架构的情况下为:select* from db limit 10,10;但是在分布式数据库这样是不行的,数据很明显会丢失,弥补的方法是查询所有,sql语句为select* from db_x limit 0,10+10//意味着需要查询的是本在单体架构上要查询的记录数加上之前的记录,然后再在内存中合并所有表返回的记录然后进行解析,最后取第10开始的记录?可以看出这个方案一旦页码数达到n页,而每页显示的记录数为m条记录的时候,每个表需要查询的记录数为:(n-1)*m+m=nm条记录,内存中需要解析的记录数为 t* n* m条记录,cpu不爆炸算我输
第三种:
采取的是基于业务的模式:迫使用户无法进行跳页查询,什么意思呢,就是用户只能点击下一页或者上一页的方式浏览,具体的做法在于查询得到记录数的同时记录下当前唯一id值的最大值,然后再次查询的时候添加where条件?让我们从头开始捋:第一次查询pageNum=1,pageSize=10,maxId=0->sql:select* from db_x where id>0 limit 10;然后分发到对应的库的表中,将得到的4*10条数据合并,再在内存中进行解析排序,取前10条数据,同时将第10条数据的id=maxId单独取出渲染到前端页面上保存,这样当点击下一页的时候,这个maxId=10也提交上去了,sql变成了select* from db_x where id>10 limit 10,然后继续解析,继续保存?这种方式返回的数据都是稳定的并且数据是连贯的(排序)
第四种:
传说中的最好的方式,支持跳页查询,这个方式核心在于2次sql查询,具体怎么做呢:
前提条件假设:查询第1001页的数据,每页显示10条记录
1):我们先记录下要查询的记录数的范围:(1001-1)*10=10000开始,10010结束->10000-10010
单体的sql为:select* from db limit 10000,10;
我们总共有4个表,意味着:每个表的start应该为10000/4=2500,从而sql变成了:
select* from db_x limit 2500,10;//假设是平均分配的,因而我们可以均分,不均分也没关系,后续操作会补齐
我们会得到4个表中的记录:(因为我demo还没写,所以先手写了)
T1:(1,"a"),.......
T2:(2,"b"),.......
T3:(3,"c"),.......
T4:(4,"d"),.......
真实数据第1001页不可能是1开头的,将就着看吧,过几天会一起讲rabbitMQ分布式一致性和这个demo一起发布的
ok,第一阶段的sql查询结束
2):对4个表中返回的记录进行id匹配(id如果非整型,自行用hashCode匹配),因为是升序查询,所以我们只需要比较下每个表的首条记录
的id值即可,获得了最小的minId=1,和各个表最大的那个值maxId;ok,转换sql思路,这里我们采用条件查询了(弥补操作第一步):
select* from db_x where id between minId and maxId这样我们就获取到了遗漏的数据(当然有多余的数据)
这样我们4个表中就返回了可能记录数各不相同的记录,第二步结束
3):
之后记录minId出现的位置,如T1出现的位置为2500,T2出现的位置为2500-2=2048,T3出现的位置为2500-3=2047,T4出现的位置
为2500-3=2047则最终出现的记录数为:2500+2048+2047+2047=10000-2-3-3=9992,因此我们需要的查询的记录数需要从9992依次往后取
8个开始,然后再取10个就是所求的数据,这种方式能做到数据精确查询,但是唯一的缺点就是每次查询都需要进行二次sql查询
文章到此结束,如果本次分享的数据库分表后怎么查询和mysql分库后怎么查询的问题解决了您的问题,那么我们由衷的感到高兴!