首页 文章 精选 留言 我的

精选列表

搜索[数据库系统],共1285篇文章
优秀的个人博客,低调大师

每日一博 | 数据库系统设计:分区

摘要:对大数据集或非常高吞吐量,仅复制还不够,还需将数据拆分成为分区,也称分片。 本文分享自华为云社区《系统设计之分区策略》,作者:JavaEdge。 对大数据集或非常高吞吐量,仅复制还不够,还需将数据拆分成为分区(partitions),也称分片(sharding)[^i]。 [^i]: 分区是一种有意将大型数据库分解成小型数据库的方式。它与网络分区(network partitions, netsplits)无关,这是节点之间网络故障的一种。后文再讨论这些错误。 术语澄清 分区 (partition),对应MongoDB、ES中的shard,HBase 的Region,Bigtable的tablet,Cassandra的vnode,Couchbase的vBucket。但分区 (partitioning)是最普遍的。 定义 每条数据(或每条记录,每行或每个文档)属于且仅属于某特定分区。每个分区都能视为一个完整小型数据库,虽然数据库可能存在跨分区操作。 目的 提高可扩展性。不同分区可放在一个无共享集群的不同节点。这样的一个大数据集可分散在更多磁盘,查询负载也随之分布到更多处理器。 单分区查询时,每个节点对自己所在分区查询可独立执行查询操作,添加更多节点就能提高查询吞吐量。大型复杂查询尽管比较困难,但也可能做到跨节点的并行处理。 分区数据库在 20 世纪 80 年代由 Teradata 和 NonStop SQL等产品率先推出,最近因NoSQL和基于Hadoop的数据仓库重新被关注。有些系统是为事务处理而设计,有些系统则用于分析:这种差异会影响系统的运作方式,但是分区的基本原理均适用于这两种工作方式。 在本章中,我们将首先介绍分割大型数据集的不同方法,并观察索引如何与分区配合。然后讨论rebalancing,若想添加、删除集群中的节点,则必须进行再rebalancing。最后,概述DB如何将请求路由到正确的分区并执行查询。 1 分区与复制 分区一般和复制搭配使用,即每个分区的多个节点都有副本。这意味着,某条记录属于特定的分区,而同样内容会存储在不同的节点上,以提高系统容错性。 一个节点可能存储多个分区。如图-1所示,主从复制模型和分区组合时数据的分布情况。每个分区都有自己的主副本,如被分配给某节点,而从库副本被分配给其他节点。一个节点可能是某些分区的主副本,同时也是其他分区的从副本。 上一个文章讨论的复制相关所有内容同样适用于分区数据的复制。考虑到分区方案的选择通常独立于复制,为简单起见,本文忽略复制相关内容。 2 KV数据的分区 海量数据想切分,如何决定在哪些节点上存储哪些记录? 分区的主要目标:将数据和查询负载均匀分布在各节点。若每个节点平均分担数据和负载,则理论上10个节点能处理10 倍的数据量和10 倍于单节点的读写吞吐量(暂忽略复制)。 但若分区不均,则会导致某些分区节点比其他分区有更多数据量或查询负载,即倾斜,这会导致分区效率下降很多。极端情况下,所有负载可能压在一个分区节点,其余9个节点空闲,系统瓶颈落在这最忙的节点。这时的高负载分区即是系统热点。 2.1 避免热点 最简单的,将记录随机分配给所有节点。这能在所有节点比较均匀分布数据,但缺点是:试图读取特定数据时,不知道保存在哪个节点,必须并行查询所有节点。 可以优化该方案。假设数据是简单的KV数据模型,即总能通过K访问记录。如在一本百科全书,可通过标题查找一个条目;而所有条目按字母序排序,因此能快速找到目标条目。 2.2 根据K的范围分区(Key Range分区策略) 一种分区方案,为每个分区指定一块连续的K范围(以min和max 指示),如纸质百科全书的卷(图-2)。若知道K区间的边界,就能轻松确定哪个分区包含这些K。若你还知道分区所在的节点,则可直接请求相应节点(就像从书架上选取正确书籍)。 K的区间不一定要均匀分布,因为数据本身可能就不均匀。如图-2中,1卷包含A、B开头的单词,但12卷则包含T、U、V、X、Y和Z开头单词。若只是简单规定每个卷包含两个字母,可能导致一些卷比其他卷大。为更均匀分布数据,分区的边界应适配数据本身的分布特征。 分区边界可由管理员手动确定或由DB自动选择。Bigtable及其开源版本HBase和2.4版本之前的MongoDB都采用该分区策略。 每个分区中,可按K排序保存。范围扫描就很简单,将K作为联合索引来处理,从而在一次查询中获取多个相关记录。假设有个程序存储网络传感器的数据,K是测量的时间戳(年月日-时分秒)。范围扫描此时很有用,可快速获取某月内的所有数据。 缺点 某些访问模式会导致热点。 若K是时间戳,则分区对应于一个时间范围,如每天一个分区。 测量数据从传感器写入DB时,所有写入操作都集中在同一分区(即当天的分区),导致该分区在写入时处于高负载,而其他分区始终空闲。 为避免该问题,需要使用时间戳之外的内容作为K的第一项。 可考虑每个时间戳前添加传感器名称,这样首先按传感器名称,再按时间进行分区。假设多个传感器同时运行,则写入负载最终会均匀分布在多个节点。 当想要获取一个时间范围内、多个传感器的数据,可根据传感器名称,各自执行单独的范围查询。 2.3 根据键的Hash分区 由于数据倾斜和热点问题,许多分布式系统采用基于K散列函数来分区。 好的散列函数可处理倾斜数据并使其均匀分布。 数据分区目的的hash函数无需健壮的加密能力,如Cassandra 和 MongoDB 使用 MD5。许多编程语言也有内置的简单哈希函数(主要用于哈希表),但可能不适合分区:如Java 的 Object.hashCode(),同一K可能在不同进程中有不同哈希值。 确定合适的hash函数后,就能为每个分区分配一个hash范围(而不是直接就是K的范围),每个K通过hash散列落在不同分区,如图-3: 这种方案擅长在分区之间均匀分配K。分区边界可以是均匀间隔,也可以是伪随机选择(也称为一致性哈希)。 一致性哈希 一种平均分配自己负载的方法,最初用于内容分发网络(CDN)等互联网缓存系统。 采用随机选择的分区边界来规避中央控制或分布式共识。此处的一致性与副本一致性或ACID一致性无任何关联 ,它只描述了数据动态平衡的一种方法。 正如“分区再平衡” 中所见,这种特殊分区方法对于DB实际上效果并非很好,所以目前很少使用(虽然某些DB的文档仍会使用一致性哈希说法,但其实不准确)。 因为有可能产生混淆,所以最好避免使用一致性哈希这个术语,而只是把它称为散列分区(hash partitioning)。 但通过hash分区,失去高效的执行范围查询的能力:即使相邻的K,经过hash后也会分散在不同分区。MongoDB中,若使用hash分区,则范围查询都必须发送到所有分区。而Couchbase或Voldemort干脆直接不支持K的范围查询。 Cassandra在两种分区策略之间采取折中。 Cassandra的表可使用由多个列组成的复合主键。键中只有第一部分可用于 hash 分区,而其他列则被用作 Casssandra 的 SSTables 中排序数据的联合索引。尽管不支持复合主键的第一列的范围查询,但若第一列已指定固定值,则可对其他列执行高效的范围查询。 联合索引为一对多关系提供一个优雅的数据模型。如社交网站,一个用户可能发布很多消息更新。若更新的K被设置为 (user_id,update_timestamp),则能高效检索某用户在某时间段内,按时间戳排序的所有更新。不同用户可存储在不同分区,但对某一用户,消息会按时间戳顺序存储在同一分区。 2.4 负载偏斜与热点消除 hash分区可减少热点,但无法完全避免:极端情况下,所有读/写操作都是针对同一K,则所有请求都会被路由到同一分区。 这种负载也许不常见,但也并非不可能:如社交网站,一个坐拥百万粉丝的大V用户,发布一些热点事件时,可能引发一场访问风暴。导致同一个K的大量写操作(K可能是大V的用户ID或人们正在评论的事件ID)。此时,hash策略不起任何作用,因为两个相同ID的hash值仍相同。 如今,大多数据系统仍无法自动消除这种高度偏斜的负载,只能通过应用层来减少倾斜。如某K被确认为热点,简单方法是在K的开始或结尾添加一个随机数。只要一个两位数的十进制随机数就能将主键分散为100种不同的K,从而存储在不同分区。 但之后的任何读取都要做额外工作,必须从所有100个K分布中读取数据然后合并。因此通常只对少量热点K附加随机数才有意义;而对写吞吐量低的大多数K,这些都是不必要开销。此外,还需额外元数据来标记哪些K进行了特殊处理。 也许将来某天,数据系统将能自动检测和处理负载倾斜情况;但当下,仍需你自己来综合权衡策略。 点击关注,第一时间了解华为云新鲜技术~

优秀的个人博客,低调大师

SQL数据库学习之路(练习)--数据库系统教程第三章练习

目录 实验要求 利用SQL语句创建数据库Lesson 通过SQL语句创建以下基本表 通过SQL语句实现以下操作: 撤销索引IDX_CLASSID及IDX_S#_C# 在学生关系中增加班级号属性列CLASSID 撤销学生关系中的班级号属性列CLASSID 撤销班级关系CLASS 利用实验1创建的数据库Lesson,分别在各表中插入以下记录,要求至少有一个表为单元组、至少有一个表为多元组的方式插入: 通过select into语句将SC表的表结构复制为SC_TEMP表,然后查询所有性别非空的学生的选课记录并将之插入到SC_TEMP表。 删除SC_TEMP表中无成绩的元组。 将SC_TEMP表中S3的低于S3平均成绩的成绩提高10% 删除SC_TEMP表中S3的小于该生平均成绩的成绩元组。 将S表中性别为空的学生的性别修改为女,并将年龄修改为25岁 创建视图V_M_STUDENT, 要求显示男学生的学号、姓名、课程名、教师名、成绩等列 ​检索学习C3课程的所有学生姓名和年龄 检索学习由教授讲授的课程的学生学号和姓名 检索没选修任何课程的学生学号 检索年龄在18到20岁之间的女学生学习的课程号和课程名 ​检索学习了C1或C3课程的学生学号 ​检索Hu同学不学的课程号 检索成绩为空的课程对应的教师号和教师姓名 检索至少有S2和S4学习的课程号 ​检索选修了S3学习的全部课程的学生学号 检索每个学生的姓名和出生年份,并将出生年份列重命名为Birth_Year 检索选修了课程的所有学生的学号,要求不显示重复结果 检索LIU老师所授课程的每门课程的人数和平均成绩 统计各门课程的最高分 统计每门课程的学生选修人数,(超过3人的课程才统计),要求显示课程号和人数,查询结构按人数升序排序,若人数相同,按课程号降序排序 查询每个学生超过他自己选修课程平均成绩的学号及课程号 把低于所有课程总平均成绩的女同学的成绩提高3% 分别用INNER JOIN 和LEFT OUTER JOIN 连接S和SC表 检索姓名中第三个字母为“N”的学生的姓名和年龄 选择C1课程的前3名的学生学号和成绩 检索平均成绩大于85的学生学号 实验要求 利用SQL语句创建数据库Lesson create database work on primary( name='work', --主数据文件的逻辑名称 filename='F:\SQL\work1\work.mdf', --主数据文件的物理名称 size=10mb, --主数据文件的初始大小 filegrowth=10mb --主数据文件的增长率 ) log on( name='work_log', --日志文件的逻辑名称 filename='F:\SQL\work1\work_log.ldf', --日志文件的物理名称 size=5mb, --日志文件的初始大小 filegrowth=10% --日志文件的增长率 ) 通过SQL语句创建以下基本表 教师关系 T(T#, TNAME,TITLE) 课程关系 C(C#,CNAME,T#) 学生关系 S(S#,SNAME,AGE,SEX) 选课关系SC(S#,C#,SCORE) 班级关系CLASS(CLASSID,CLASSNAME) 其中红色粗体为主键,带下划线的属性为外键。 通过SQL语句在CLASS表的CLASSID列上创建聚集索引IDX_CLASSID 通过SQL语句创建在S#和C#两个列上创建索引IDX_S#_C#,并指定索引按S#降序,C#升序有序。 create table T --创建表教师关系T (T# char(4) not null, TNAME char(8) not null, TITLE char(10), PRIMARY KEY(T#) --设置主键为T# ); create table C --创建表课程关系T (C# char(4), CNAME char(10) not null, T# char(4), PRIMARY KEY(C#), --设置主键为C# FOREIGN KEY(T#)REFERENCES T(T#) --设置外键为T# ); create table S --创建表学生关系S (S# char(4) not null, SNAME char(8) not null, AEG char(1), PRIMARY KEY(S#) --设置主键为S# ); create table SC --创建表选课关系SC (S# char(4), C# char(4), SCORE SMALLINT, PRIMARY KEY(S#,C#), --设置主键为S#,C# FOREIGN KEY(S#)REFERENCES S(S#), ----设置外键为S# FOREIGN KEY(C#)REFERENCES C(C#) ----设置外键为C# ); create table class --创建表班级关系class ( CLASSID char(4), CLASSNAME char(8) ); 通过SQL语句实现以下操作: 撤销索引IDX_CLASSID及IDX_S#_C# create unique index IDX_CLASSID on class(CLASSID); --在CLASS表的CLASSID列上创建聚集索引IDX_CLASSID create unique index IDX_S#_C# on SC(S# DESC,C# ASC); --创建在S#和C#两个列上创建索引IDX_S#_C#,并指定索引按S#降序,C#升序有序 DROP INDEX IDX_CLASSID on class; --撤销索引IDX_CLASSID DROP INDEX IDX_S#_C# on SC; --撤销索引IDX_S#_C# 在学生关系中增加班级号属性列CLASSID alter table S add CLASSID char(4); --在学生关系中增加班级号属性列CLASSID 撤销学生关系中的班级号属性列CLASSID alter table S drop column CLASSID; --撤销学生关系中的班级号属性列CLASSID 撤销班级关系CLASS drop table class ; --撤销班级关系CLASS 利用实验1创建的数据库Lesson,分别在各表中插入以下记录,要求至少有一个表为单元组、至少有一个表为多元组的方式插入: S表 C表 SC表 T表 insert S(S#,SNAME,AEG,sex) values('s1','WANG','20','男'), ('s2','LIU','18','女'), ('s3','HU','17','男'), ('s4','XIA','19',NULL), ('s5','SUN','20','男'), ('s6','ZHAO',NULL,'男'), ('s7','DENG',NULL,'女') insert C(C#,CNAME,T#) values ('c1','OS','t2') insert C(C#,CNAME,T#) values ('c2','java','t1') insert C(C#,CNAME,T#) values ('c3','C++','t1') insert C(C#,CNAME,T#) values ('c4','C','t3') insert SC(S#,C#,SCORE) values('s1','c1','80'), ('s1','c2','53'), ('s1','c3',NULL), ('s1','c4','68'), ('s2','c1','85'), ('s3','c1','85'), ('s3','c3','83'), ('s3','c4','75'), ('s4','c1','79'), ('s4','c2','92'), ('s5','c1',NULL), ('s5','c2','45') insert T(T#,TNAME,TITLE) values('t1','LIU','教授'), ('t2','ZHANG','副教授'), ('t3','LI','教授'), ('t4','ZHAO','讲师') 通过select into语句将SC表的表结构复制为SC_TEMP表,然后查询所有性别非空的学生的选课记录并将之插入到SC_TEMP表。 select *into SC_TEMP from SC where 1=2 insert into SC_TEMP select *from SC where S# in(select S# from S where sex is not NULL) 删除SC_TEMP表中无成绩的元组。 delete from SC_TEMP where SCORE is NULL --删除SC_TEMP表中成绩为NULL的元组 将SC_TEMP表中S3的低于S3平均成绩的成绩提高10% --将SC_TEMP表中S3的低于S3平均成绩的成绩提高10% update SC_TEMP set SCORE =1.1*SCORE where SCORE <(select AVG(SCORE) from SC_TEMP where S#='s3') and S#='s3' 删除SC_TEMP表中S3的小于该生平均成绩的成绩元组。 --删除SC_TEMP表中S3的小于该生平均成绩的成绩元组。 delete from SC_TEMP where SCORE <(select AVG(SCORE) from SC_TEMP where S#='s3') and S#='s3' 将S表中性别为空的学生的性别修改为女,并将年龄修改为25岁 update S set [sex]='女', [AEG]='25' where sex is NULL 创建视图V_M_STUDENT, 要求显示男学生的学号、姓名、课程名、教师名、成绩等列 create view V_M_STUDENT(S#,SNAME,CNAME,TNAME,SCORE) as select S.S#,SNAME,CNAME,TNAME,SCORE from S,C,T,SC where S.S#=SC.S# AND SC.C#=C.C# AND C.T#=T.T# 检索学习C3课程的所有学生姓名和年龄 --1)检索学习C3课程的所有学生姓名和年龄 select S.SNAME,S.AEG from S,SC where S.S#=SC.S# and SC.C#='c3' 检索学习由教授讲授的课程的学生学号和姓名 --2)检索学习由教授讲授的课程的学生学号和姓名 Select DISTINCT S.S#,S.SNAME from S,SC,C,T where T.TITLE='教授' AND T.T#=C.T# AND C.C#=SC.C# AND SC.S#=S.S# 检索没选修任何课程的学生学号 --3)检索没选修任何课程的学生学号 select S.S# from S where S.S# NOT IN (SELECT S# FROM SC) 检索年龄在18到20岁之间的女学生学习的课程号和课程名 --4)检索年龄在18到20岁之间的女学生学习的课程号和课程名 SELECT DISTINCT C.C#,C.CNAME FROM C,SC WHERE C.C#=SC.C# AND SC.S# IN(SELECT S# FROM S WHERE S.AEG BETWEEN 18 AND 20) 检索学习了C1或C3课程的学生学号 --5)检索学习了C1或C3课程的学生学号 SELECT DISTINCT S.S# FROM S,SC WHERE S.S# LIKE SC.S# AND (SC.C#='c1' or SC.C#='c3') 检索Hu同学不学的课程号 --6)检索Hu同学不学的课程号 SELECT C.C# FROM C WHERE C.C# NOT IN (SELECT C# FROM SC,S WHERE SC.S# LIKE S.S# AND S.SNAME='HU') 检索成绩为空的课程对应的教师号和教师姓名 --7)检索成绩为空的课程对应的教师号和教师姓名 SELECT T.T#,T.TNAME FROM T WHERE T.T# IN (SELECT C.T# FROM C,SC WHERE C.C# LIKE SC.C# AND SC.SCORE IS NULL) 检索至少有S2和S4学习的课程号 --8)检索至少有S2和S4学习的课程号 SELECT DISTINCT SC.C# FROM SC WHERE SC.C# IN ((SELECT SC.C# FROM SC WHERE SC.S# like 's2') INTERSECT (SELECT SC.C# FROM SC WHERE SC.S# like 's4')) 检索选修了S3学习的全部课程的学生学号 --9)检索选修了S3学习的全部课程的学生学号 SELECT DISTINCT SC.S# FROM SC WHERE SC.C# IN (SELECT SC.C# FROM SC WHERE SC.S# LIKE 's3') 检索每个学生的姓名和出生年份,并将出生年份列重命名为Birth_Year --10)检索每个学生的姓名和出生年份,并将出生年份列重命名为Birth_Year SELECT S.SNAME,2018-S.AEG AS Birth_Year FROM S 检索选修了课程的所有学生的学号,要求不显示重复结果 --1)检索选修了课程的所有学生的学号,要求不显示重复结果 SELECT DISTINCT SC.S# FROM SC 检索LIU老师所授课程的每门课程的人数和平均成绩 --2)检索LIU老师所授课程的每门课程的人数和平均成绩。 SELECT C.C#,COUNT(DISTINCT SC.S#),AVG(SC.SCORE) FROM C,T,SC WHERE C.T#=T.T# AND C.C#=SC.C# AND TNAME='LIU' GROUP BY C.C#; 统计各门课程的最高分 --3)统计各门课程的最高分。 SELECT SC.C#,MAX(SC.SCORE) FROM SC GROUP BY SC.C# 统计每门课程的学生选修人数,(超过3人的课程才统计),要求显示课程号和人数,查询结构按人数升序排序,若人数相同,按课程号降序排序 --4)统计每门课程的学生选修人数,(超过3人的课程才统计),要求显示课程号和人数,查询结构按人数升序排序,若人数相同,按课程号降序排序。 SELECT DISTINCT C#,COUNT(DISTINCT S#) AS 人数 FROM SC GROUP BY C# HAVING COUNT(S#)>3 ORDER BY COUNT(DISTINCT S#) asc,C# 查询每个学生超过他自己选修课程平均成绩的学号及课程号 --5)查询每个学生超过他自己选修课程平均成绩的学号及课程号。 SELECT X.S#,X.C# FROM SC AS X WHERE X.SCORE >(SELECT AVG(Y.SCORE) FROM SC AS Y WHERE X.S# =Y.S# ) 把低于所有课程总平均成绩的女同学的成绩提高3% --6)把低于所有课程总平均成绩的女同学的成绩提高3% --SELECT SC.SCORE FROM SC,S WHERE SC.S# LIKE S.S# AND S.sex='女' AND SC.SCORE>(SELECT AVG(SC.SCORE) FROM SC) UPDATE SC SET SC.SCORE=SC.SCORE*1.03 WHERE SC.SCORE LIKE (SELECT SC.SCORE FROM SC,S WHERE SC.S# LIKE S.S# AND S.sex='女' AND SC.SCORE<(SELECT AVG(SC.SCORE) FROM SC)) 分别用INNER JOIN 和LEFT OUTER JOIN 连接S和SC表 --INNER JOIN 仅对满足连接条件的CROSS中的列 LEFT OUTER JOIN 一个表满足条件的行,和另一个表的所有行 SELECT *FROM S INNER JOIN SC on S.S#=SC.S# SELECT *FROM S LEFT OUTER JOIN SC on S.S#=SC.S# 检索姓名中第三个字母为“N”的学生的姓名和年龄 --8)检索姓名中第三个字母为“N”的学生的姓名和年龄。 SELECT S.SNAME,S.AEG FROM S WHERE S.SNAME LIKE '__N%' 选择C1课程的前3名的学生学号和成绩 --9) 选择C1课程的前3名的学生学号和成绩。 SELECT TOP(3) SC.S#,SC.SCORE FROM SC WHERE SC.C# LIKE 'c1' ORDER BY SC.SCORE DESC 检索平均成绩大于85的学生学号 --10) 检索平均成绩大于85的学生学号。 SELECT DISTINCT X.S# FROM SC AS X WHERE 85<= ALL(SELECT AVG(Y.SCORE) FROM SC AS Y WHERE Y.S#=X.S# GROUP BY Y.S#)

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册