八股文学习一(存储)

一. 存储

行式存储的原理与特点

对于 OLAP 场景,大多都是对一整行记录进行增删改查操作的,那么行式存储采用以行的行式在磁盘上存储数据就是一个不错的选择。

当查询基于需求字段查询和返回结果时,由于这些字段都埋藏在各行数据中,就必须读取每一条完整的行记录,大量磁盘转动寻址的操作使得读取效率大大降低。

举个例子,下图为员工信息emp表。

数据在磁盘上是以行的形式存储在磁盘上,同一行的数据紧挨着存放在一起。

对于 emp 表,要查询部门 dept 为 A 的所有员工的名字。

select name from emp where dept = A

由于 dept 的值是离散地存储在磁盘中,在查询过程中,需要磁盘转动多次,才能完成数据的定位和返回结果。

列式存储的原理与特点

对于 OLAP 场景,一个典型的查询需要遍历整个表,进行分组、排序、聚合等操作,这样一来行式存储中把一整行记录存放在一起的优势就不复存在了。而且,分析型 SQL 常常不会用到所有的列,而仅仅对其中某些需要的的列做运算,那一行中无关的列也不得不参与扫描。

然而在列式存储中,由于同一列的数据被紧挨着存放在了一起,如下图所示。

那么基于需求字段查询和返回结果时,就不许对每一行数据进行扫描,按照列找到需要的数据,磁盘的转动次数少,性能也会提高。

还是上面例子中的查询,由于在列式存储中 dept 的值是按照顺序存储在磁盘上的,因此磁盘只需要顺序查询和返回结果即可。

列式存储不仅具有按需查询来提高效率的优势,由于同一列的数据属于同一种类型,如数值类型,字符串类型等,相似度很高,还可以选择使用合适的编码压缩可减少数据的存储空间,进而减少IO提高读取性能。

总的来说,行式存储和列式存储没有说谁比谁更优越,只能说谁更适合哪种应用场景。

1.1 mysql

当数据库上有多个事务同时执行的时候,就可能出现脏读(dirty read)、不可重复读(non- repeatable read)、幻读(phantomread)的问题,为了解决这些问题,就有了“隔离级别”的概念。

脏读:如果一个事务A对数据进行了更改,但是还没有提交,而另一个事务B就可以读到事务A尚未提交的更新结果。这样,当事务A进行回滚时,那么事务B开始读到的数据就是一笔脏数据。
不可重复读:同一个事务对同一个数据进行读取操作,读取到的结果不同。例如,事务B在事务A的更新操作前读到的数据,跟在事务A提交此更新操作后读到的数据,可能不同。
幻读:就是一个事务读到另一个事务新增加并提交的数据(insert)。在同一个事务中,对于同一组数据读取到的结果不一致。比如,事务A 新增了一条记录,事务B 在 事务A 提交前后各执行了一次查询操作,发现后一次比前一次多了一条记录。幻读出现的原因就是由于事务并发新增记录而导致的。


不可重复读和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于删除或新增!!

下面我们来看为了解决这些问题出现的隔离级别。首先要知道,隔离得越严实,效率就会越低。因此很多时候,我们都要 在二者之间寻找一个平衡点。SQL标准的事务隔离级别包括:读未提交(read uncommitted)、 读提交(read committed)、可重复读(repeatable read)和串行化(serializable )。 具体解释如下:

读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到。
读已提交是指,一个事务提交之后,它做的变更才会被其他事务看到。
可重复读是指,一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一 致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。
串行化,顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突 的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

 
数据库的隔离性就是通过加锁和MVCC来实现的。从上面可以看到,可重复读的隔离级别会出现幻读的问题,而MySQL的默认隔离级别是可重复读,并且解决了幻读的问题。简单来说,MySQL的默认隔离级别解决了脏读、幻读、不可重复读的问题。

MySQL事务及实现原理全面总结,再也不用担心面试_mysql事务的实现原理_李孛欢的博客-CSDN博客

https://www.rstk.cn/news/99075.html?action=onClick

mysql锁(面试必备),值得收藏!_mysql锁面试-CSDN博客

1.2. hbase 

(1)特点:

Base不支持二级索引,它只有一个主键索引,采用LSM树。

HBase是一个分布式系统,这点跟MySQL不同,它的数据是分散不同的server上,每个table由一个或多个region组成,region分散在集群中的server上,一个server可以负责多个region。

这里有一点需要特别注意:table中各个region的存放数据的rowkey(主键)范围是不会重叠的,可以认为region上数据基于rowkey全局有序,每个region负责它自己的那一部分的数据。

1.查询

查询操作是根据rowkey返回时间戳最大的数据。假如我们要查询rowkey=150的这条记录,首先从zk中获取hbase:meta表(存放region和key的对应关系的元数据表)的位置,通过查询meta表得知rowkey=150的数据在哪个server的哪个region上。

2.插入

上图粗略的展示了HBase的region的结构,region不单单是一个文件,它是由一个memstore和多个storeFile组成(storeFile上的上限可以配置)。插入数据时首先将数据写入memstore,当memstore大小达到一定阈值,将memstore flush到硬盘,变成一个新的storeFile。flush的时候会对memstore中的数据进行排序,压缩等操作。可以看到单个storeFile中的数据是有序的,但是region中的storeFile间的数据不是全局有序的。

这样有的好处就是:不管主键是否连续,所有的插入一律变成顺序写,大大提高了写入性能。

看到这里大家可能会有一个疑问:这种写入方式导致了一条记录如果不是一次性插入,很可能分散在不同的storeFile中,那在该region上面查询一条记录时,怎么知道去找哪个storeFile呢?答案就是:全部查询。HBase会采用多路归并的方式,对该region上的所有storeFile进行查询,直到找到符合条件的记录。所以HBase的拥有很好的写入性能,但是读性能较差。

当然HBase也做了很多优化,比如每个storeFile都有自己的index、用于过滤的bloom filter、compaction:按可配置的方式将多个storeFile合并成一个,减少检索时打开的文件数。

3.更新 & 删除

修改操作其实是根据时间戳重新put一条数据。删除操作其实是PUT一条操作类型为DEL的数据。(当查询时发现该row key的最大时间戳记录操作类型为DEL,则不返回数据,给用户造成的感觉就是已删除该row key)。因此也造成数据冗余。

HBase将更新和删除也全部看做插入操作,用timestamp和delete marker来区分该记录是否是最新记录、是否需要删除。也正是因为这样,除了查询,其他的操作统一转换成了顺序写,保证了HBase高效的写性能。

(2)适用场景:

mysql与hbase 解决问题定位不同

MySQL解决应用的在线事务问题。

Hbase解决大数据场景的海量存储问题。

HBase 不是 MySQL 的替换,HBase 是业务规模及场景扩张后,对 MySQL 的自然延伸。

参考文章:

https://www.cnblogs.com/datadance/p/16327298.html

一文读懂Hive底层数据存储格式(好文收藏)-腾讯云开发者社区-腾讯云

https://cloud.tencent.com/developer/article/1888531

https://www.cnblogs.com/ityouknow/p/7344001.html

从原理到应用解释MYSQL和HBASE区别 - 掘金

入门Hbase,看这一篇就够了 - 掘金

3.es

(1)写流程

a. 先写入buffer,在buffer里的时候数据是搜索不到的;同时将数据写入translog日志文件

b. 如果buffer快满了,或者到一定时间,就会将buffer数据refresh到一个新的segment file中,但是此时数据不是直接进入segment file的磁盘文件的,而是先进入os cache的。这个过程就是refresh。

c.只要数据进入os cache,此时就可以让这个segment file的数据对外提供搜索了

d. 如果是删除操作,commit的时候会生成一个.del文件,里面将某个doc标识为deleted状态,那么搜索的时候根据.del文件就知道这个doc被删除了

e. 如果是更新操作,就是将原来的doc标识为deleted状态,然后新写入一条数据

f. buffer每次refresh一次,就会产生一个segment file,所以默认情况下是1秒钟一个segment file,segment file会越来越多,此时会定期执行merge

g. 每次merge的时候,会将多个segment file合并成一个,同时这里会将标识为deleted的doc给物理删除掉,然后将新的segment file写入磁盘,这里会写一个commit point,标识所有新的segment file,然后打开segment file供搜索使用,同时删除旧的segment file。

es里的写流程,有4个底层的核心概念,refresh、flush、translog、merge
 

(2)读流程

a. 客户端发送请求到一个coordinate node
b. 协调节点将搜索请求转发到所有的shard对应的primary shard或replica shard也可以
c. query phase:每个shard将自己的搜索结果(其实就是一些doc id),返回给协调节点,由协调节点进行数据的合并、排序、分页等操作,产出最终结果
d. fetch phase:接着由协调节点,根据doc id去各个节点上拉取实际的document数据(根据doc id进行hash路由到对应的primary shard上面去),最终返回给客户端

(3)分页
如果每页展示 5 条结果,可以用下面方式请求得到 1 到 3 页的结果:

GET /_search?size=5
GET /_search?size=5&from=5
GET /_search?size=5&from=10

Size:显示应该返回的结果数量,默认是 10
From:显示应该跳过的初始结果数量,默认是 0
深度分页

理解为什么深度分页是有问题的,我们可以假设在一个有 5 个主分片的索引中搜索。
 当我们请求结果的第一页(结果从 1 到 10 ),每一个分片产生前 10 的结果,并且返
 回给协调节点 ,协调节点对 50 个结果排序得到全部结果的前 10 个。现在假设我们请
 求第1000 页—​结果从 10001 到 10010 。所有都以相同的方式工作除了每个分片不得不
 产生前10010个结果以外。 然后协调节点对全部 50050 个结果排序最后丢弃掉这些结果
 中的50040 个结果。可以看到,在分布式系统中,对结果排序的成本随分页的深度成指数
 上升。这就是 web 搜索引擎对任何查询都不要返回超过 1000 个结果的原因。


(4)倒排索引

它适用于快速的全文搜索。一个倒排索引由文档中所有不重复词的列表构成,对于其中每个
词,有一个包含它的文档列表。
	Term  | Doc 1 | Doc 2 | Doc 3 | ...
	------------------------------------
	brown |   X   |       |  X    | ...
	fox   |   X   |   X   |  X    | ...
	quick |   X   |   X   |       | ...
	the   |   X   |       |  X    | ...

要构建倒排索引,需要对文档内容分析并分词,分析过程如下:

    首先,将一块文本分成适合于倒排索引的独立的 词条 ,
    之后,将这些词条统一化为标准格式以提高它们的“可搜索性”。

分析器执行上面的工作,由以下三部分构成:

字符过滤器:
    首先,字符串按顺序通过每个 字符过滤器 。他们的任务是在分词前整理字符串。一个
字符过滤器可以用来去掉HTML,或者将 & 转化成 and。

分词器:
    其次,字符串被 分词器 分为单个的词条。一个简单的分词器遇到空格和标点的时候,
可能会将文本拆分成词条。

Token 过滤器:
    最后,词条按顺序通过每个 token 过滤器 。这个过程可能会改变词条(例如,小写
化 Quick ),删除词条(例如, 像 a, and, the 等无用词),或者增加词条(例如,
像 jump 和 leap 这种同义词)。

Elasticsearch 中的文档是有字段和值的结构化 JSON 文档。事实上,在 JSON 文档中, 每个被索引的字段都有自己的倒排索引。

倒排索引,是通过分词策略,形成了词和文章的映射关系表,这种词典+映射表即为倒排索引。
有了倒排索引,就能实现o(1)时间复杂度的效率检索文章了,极大的提高了检索效率。

学术的解答方式:

倒排索引,相反于一篇文章包含了哪些词,它从词出发,记载了这个词在哪些文档中出现过,由两部分组成——词典和倒排表。

加分项:倒排索引的底层实现是基于:FST(Finite State Transducer)数据结构。
lucene从4+版本后开始大量使用的数据结构是FST。FST有两个优点:

1)空间占用小。通过对词典中单词前缀和后缀的重复利用,压缩了存储空间;
2)查询速度快。O(len(str))的查询时间复杂度。

(5)扩容

方案:

新建索引 + 索引别名 +多索引检索


依据:

    搜索 1 个有着 50 个分片的索引与搜索 50 个每个都有 1 个分片的索引完全等价:
搜索请求均命中 50 个分片


步骤:

a、假设原有索引tweets_1只有一个分片;

b、为索引添加别名:tweets_search 、tweets_index
    PUT /tweets_1/_alias/tweets_search 
    PUT /tweets_1/_alias/tweets_index 
    
c、tweets_1容量不够,需新建索引tweets_2,规划5个分片;

d、别名指向新的索引;
    POST /_aliases
    {
        "actions": [
             { "add":    { "index": "tweets_2", "alias": "tweets_search" }}, 
            { "remove": { "index": "tweets_1", "alias": "tweets_index"  }}, 
            { "add":    { "index": "tweets_2", "alias": "tweets_index"  }}  
        ]
    }
    说明:
    tweets_search:指向tweets_2、tweets_1两个索引。
        (一个搜索请求可以以多个索引为目标,所以将搜索别名指向 tweets_1 以及
    tweets_2 是完全有效的)
    
    tweets_index:由 tweets_1 切换至 tweets_2
        (索引写入请求只能以单个索引为目标,必须将索引写入的别名只指向新的索引)

(6)索引分片数确认

索引主分片数一旦确定,不可更改,es会根据路由字段对应hash值确定将数据放在哪个分片上

对大数据集, 我们非常鼓励你为索引多分配些分片--当然也要在合理范围内. 上面讲到的每个分片最好不超过30GB的原则依然使用.

不过, 你最好还是能描述出每个节点上只放一个索引分片的必要性. 在开始阶段, 一个好的方案是根据你的节点数量按照1.5~3倍的原则来创建分片. 例如,如果你有3个节点, 则推荐你创建的分片数最多不超过9(3x3)个.

随着数据量的增加,如果你通过集群状态API发现了问题,或者遭遇了性能退化,则只需要增加额外的节点即可. ES会自动帮你完成分片在不同节点上的分布平衡.

再强调一次, 虽然这里我们暂未涉及副本节点的介绍, 但上面的指导原则依然使用: 是否有必要在每个节点上只分配一个索引的分片. 另外, 如果给每个分片分配1个副本, 你所需的节点数将加倍. 如果需要为每个分片分配2个副本, 则需要3倍的节点数. 更多详情可以参考基于副本的集群.

索引副本的作用

副本的作用一是提高系统的容错性,当某个节点某个分片损坏或丢失时可以从副本中恢复。二是提高es的查询效率,es会自动对搜索请求进行负载均衡。

(7)滚动创建索引 rollover

索引模板 template

Elastic_Search 实现索引按周期自动创建_es 自动创建索引_会编程的老六的博客-CSDN博客
ElasticSearch(十)------使用索引别名和Rollover滚动创建索引_es highlevelclient rollover-CSDN博客
 

(8)路由机制

假设你有一个100个分片的索引。当一个请求在集群上执行时会发生什么呢?

1. 这个搜索的请求会被发送到一个节点
2. 接收到这个请求的节点,将这个查询广播到这个索引的每个分片上(可能是主分片,也可能是复本分片)
3. 每个分片执行这个搜索查询并返回结果
4. 结果在通道节点上合并、排序并返回给用户

因为默认情况下,Elasticsearch使用文档的ID(类似于关系数据库中的自增ID),如果插入数据量比较大,文档会平均的分布于所有的分片上,这导致了Elasticsearch不能确定文档的位置,

所以它必须将这个请求广播到所有的N个分片上去执行 这种操作会给集群带来负担,增大了网络的开销;

当然,很多时候自定义路由是为了减少查询时扫描shard的个数,从而提高查询效率。默认查询接口会搜索所有的shard,但也可以指定routing字段,这样就只会查询routing计算出来的shard,提高查询速度。

https://www.cnblogs.com/caoweixiong/p/12029789.html

(8)elasticsearch 索引数据多了怎么办,如何调优,部署?
面试官:想了解大数据量的运维能力。
解答:索引数据的规划,应在前期做好规划,正所谓“设计先行,编码在后”,这样才能有效的避免突如其来的数据激增导致集群处理能力不足引发的线上客户检索或者其他业务受到影响。
如何调优,正如问题1所说,这里细化一下:

1)动态索引层面
基于模板+时间+rollover api滚动创建索引,举例:设计阶段定义:blog索引的模板格式为:blog_index_时间戳的形式,每天递增数据。

这样做的好处:不至于数据量激增导致单个索引数据量非常大,接近于上线2的32次幂-1,索引存储达到了TB+甚至更大。

一旦单个索引很大,存储等各种风险也随之而来,所以要提前考虑+及早避免。

2)存储层面
冷热数据分离存储,热数据(比如最近3天或者一周的数据),其余为冷数据。
对于冷数据不会再写入新数据,可以考虑定期force_merge加shrink压缩操作,节省存储空间和检索效率。

3) 部署层面
一旦之前没有规划,这里就属于应急策略。
结合ES自身的支持动态扩展的特点,动态新增机器的方式可以缓解集群压力,注意:如果之前主节点等规划合理,不需要重启集群也能完成动态新增的。

分布式集群 - 应对故障 - 《Elasticsearch 权威指南中文版》 - 技术池(jishuchi.com)

分布式搜索引擎Elasticsearch解析 - 知乎

4.redis

(1)特点

Redis是一个完全开源、遵守BSD协议、简单、高效的、分布式的、基于内存的k-v数据库。

  • 性能极高 -Redis读速度110000次/s,写的速度81000次/s。
  • 丰富的数据类型 -Redis支持的数据类型 String,Hash,List,Set及Ordered Set数据乐西操作。
  • 原子性 -Redis的所有的操作都是原子性的,意思就是要么成功,要么失败。单个操作是原子性的,多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
  • 丰富的特性 -Redis还支持 publis/subscribe,通知,key过期等等特性
  • 高速读写 -Redis使用自己实现的分离器,代码量很短,没有使用lock(Mysql),因此效率非常高。
     

(2)应用场景

1、缓存
缓存现在几乎是所有大中型网站都在用的必杀技,合理利用缓存提升网站的访问速度,还能大大降低数据库的访问压力。Redis提供了键过期功能,也提供了灵活的键淘汰策略,所以,现在Redis用在缓存的场合非常多。

2、排行榜
Redis提供的有序集合数据类结构能够实现复杂的排行榜应用。

3、计数器
视频网站的播放量,每次浏览+1,并发量高时如果每次都请求数据库操作无疑有很大挑战和压力。Redis提供的incr命令来实现计数器功能,内存操作,性能非常好,非常适用于这些技术场景。

4、分布式会话
相对复杂的系统中,一般都会搭建Redis等内存数据库为中心的session服务,session不在由容器管理,二十由session服务及内存数据管理。

5、分布式锁
在并发高的场景中,可以利用Redis的setnx功能来编写分布式锁,如果设置返回1,说明获得锁成功,否则获得锁失败。

6、社交网络
点赞、踩、关注/被关注,共同好友等是社交网站的基本功能,社交网站的访问量通常来说比较大,而且传统的关系数据库不适合这种类型的数据,Redis提供的哈希,集合等数据结构很方便的实现这些功能。

7、最新列表
Redis列表结构,LPUSH可以在列表头部插入一个内容ID作为关键字,LTRIM可以用来限制列表的数量,这样列表永远为N,无需查询最新的列表,直接根据ID去对应的内容即可。

8、消息系统
消息队列是网站经常用的中间件,如ActiveMQ,RabbitMQ,Kafka等流行的消息队列中间件,主要用于业务解耦,流量削峰以及异步处理实时性低的业务,Redis提供了发布/订阅及阻塞队列功能,能实现一个简单的消息队列系统。另外,这个不能和专业的消息中间件相比。

(3)数据类型

Redis支持的数据类型:

  1. string(字符串)
  2. hash(哈希)
  3. list(列表)
  4. set(集合)
  5. zset(sorted set:有序集合)等

(4)Redis 缓存雪崩、缓存击穿、缓存穿透

1.缓存雪崩

大量缓存数据在同一时间过期(失效)或者 Redis 故障宕机时,如果此时有大量的用户请求,都无法在 Redis 中处理,于是全部请求都直接访问数据库,从而导致数据库的压力骤增。

解决方案:

(1)缓存失效时,加锁排队

(2)数据预热

2.缓存击穿

如果缓存中的某个热点数据过期了,此时大量的请求访问了该热点数据,就无法从缓存中读取,直接访问数据库,数据库很容易就被高并发的请求冲垮,这就是缓存击穿的问题。

解决方案:

(1)互斥锁方案,保证同一时间只有一个业务线程更新缓存,未能获取互斥锁的请求,要么等待锁释放后重新读取缓存,要么就返回空值或者默认值。

(2)不给热点数据设置过期时间,由后台异步更新缓存,或者在热点数据准备要过期前,提前通知后台线程更新缓存以及重新设置过期时间;

3.缓存穿透

当用户访问的数据,既不在缓存中,也不在数据库中,导致请求在访问缓存时,发现缓存缺失,再去访问数据库时,发现数据库中也没有要访问的数据,没办法构建缓存数据,来服务后续的请求。那么当有大量这样的请求到来时,数据库的压力骤增,这就是缓存穿透的问题。

解决方案:

(1)限制非法请求

(2)缓存空值或默认值

(3)使用布隆过滤器快速判断数据是否存在,避免通过查询数据库来判断数据是否存在

(5)redis数据结构以及实现原理

万字长文的Redis五种数据结构详解(理论+实战),建议收藏。 - 文章详情

超详细Redis数据结构底层实现原理介绍_Java_蘑菇睡不着_InfoQ写作社区

Redis 键(key) | 菜鸟教程

Redis 原理+知识点总结_redis计数器_冷岫烟的博客-CSDN博客

布隆过滤器的原理是什么? - 知乎

Redis 缓存淘汰策略 - 阅读清单 - 腾讯云开发者社区-腾讯云

百度安全验证

(5)Redis实现分布式锁及相关问题

一般来说,实现分布式锁的方式有以下几种:

  • 使用 MySQL,基于唯一索引。
  • 使用 ZooKeeper,基于临时有序节点。
  • 使用 Redis,基于 setnx 命令。

我们可以为这个锁加上一个超时时间为此,我们可以为这个锁加上一个超时时间

执行 SET key value EX seconds 的效果等同于执行 SETEX key seconds value
执行 SET key value PX milliseconds 的效果等同于执行 PSETEX key milliseconds value
 

问题一:某线程 A 获取了锁并且设置了过期时间为 10s,然后在执行业务逻辑的时候耗费了 15s,此时线程 A 获取的锁早已被 Redis 的过期机制自动释放了在线程A获取锁并经过 10s 之后,改锁可能已经被其它线程获取到了。当线程 A 执行完业务逻辑准备解锁(DEL key)的时候,有可能删除掉的是其它线程已经获取到的锁。当解锁时,也就是删除 key 的时候先判断一下 key 对应的 value 是否等于先前设置的值,如果相等才能删除 key。

最后,这里我们还是一眼就可以看出问题来:GET和DEL是两个分开的操作,在 GET 执行之后且在 DEL 执行之前的间隙是可能会发生异常的,我们引入了一种新的方式,就是 Lua 脚本,解决原子性的问题。Redis 会将整个 Lua 脚本作为一个整体执行,中间不会被其他请求插入。

问题二:为了防止多个线程同时执行业务代码,需要确保过期时间大于业务执行时间,可以在代码增加一个线程用于刷新定时过期时间,并增加一个 bool 类型的值表示是否开启定时刷新过期时间,在线程获取锁的时候,将其设置为 true,解锁前设置回 false。比如,Redisson 实现,获取锁成功就会开启一个定时任务,定时任务会定期检查去续期。

问题三:在集群中,主节点挂掉时,从节点会取而代之,客户端上却并没有明显感知。原先第一个客户端在主节点中申请成功了一把锁,但是这把锁还没有来得及同步到从节点,主节点突然挂掉了。然后从节点变成了主节点,这个新的节点内部没有这个锁,所以当另一个客户端过来请求加锁时,立即就批准了。这样就会导致系统中同样一把锁被两个客户端同时持有,不安全性由此产生。此处可以用 RedLock 算法解决。
Redis系列:使用Redis实现分布式锁及相关问题_redis集群分布式锁问题_栗筝i的博客-CSDN博客

二. 大数据

1.presto

Presto是FaceBook开源的分布式SQL引擎,适用于交互查询分析,Presto 本身并不存储数据,但是可以接入多种数据源,并且支持跨数据源的级联查询。Presto是一个OLAP的工具,擅长对海量数据进行复杂的分析;但是对于OLTP场景,并不是Presto所擅长,所以不要把Presto当做数据库来使用。

2.click house

ClickHouse 是由俄罗斯搜索引擎公司 Yandex 开发的一个列式数据库管理系统,它专注于大规模数据的快速查询和分析。

特性:采用列式存储;数据压缩;基于磁盘的存储,大部分列式存储数据库为了追求速度,会将数据直接写入内存,按时内存的空间往往很小;CPU 利用率高,在计算时会使用机器上的所有 CPU 资源;支持分片,并且同一个计算任务会在不同分片上并行执行,计算完成后会将结果汇总;支持SQL,SQL 几乎成了大数据的标准工具,使用门槛较低;支持联表查询;支持实时更新;自动多副本同步;支持索引;分布式存储查询。

适用于单宽表查询。

  • clickhouse为什么如此快

1)优秀的代码,对性能的极致追求

clickhouse是CPP编写的,代码中大量使用了CPP最新的特性来对查询进行加速。

2)优秀的执行引擎以及存储引擎

clickhouse是基于列式存储的,使用了向量化的执行引擎,利用SIMD指令进行处理加速,同时使用LLVM加快函数编译执行,当然了Presto也大量的使用了这样的特性。

3)稀疏索引

相比于传统基于HDFS的OLAP引擎,clickhouse不仅有基于分区的过滤,还有基于列级别的稀疏索引,这样在进行条件查询的时候可以过滤到很多不需要扫描的块,这样对提升查询速度是很有帮助的。

4)存储执行耦合

存储和执行分离是一个趋势,但是存储和执行耦合也是有优势的,避免了网络的开销,CPU的极致压榨加上SSD的加持,每秒的数据传输对于网络带宽的压力是非常大的,耦合部署可以避免该问题。

5)数据存储在SSD,极高的iops。

百度安全验证

趣头条基于ClickHouse玩转每天1000亿数据量 - 知乎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python深度学习八股文是指在进行深度学习任务时,经常要涉及的一些基本步骤和常用技术。下面是一个通用的Python深度学习八股文的示例: 1. 导入所需的库: ```python import numpy as np import pandas as pd import tensorflow as tf from tensorflow.keras import layers, models ``` 2. 准备数据: ```python X_train = ... # 输入特征训练集 y_train = ... # 标签训练集 X_test = ... # 输入特征测试集 y_test = ... # 标签测试集 ``` 3. 数据预处理: ```python # 特征归一化 X_train = (X_train - X_train.mean()) / X_train.std() X_test = (X_test - X_train.mean()) / X_train.std() # 标签转换为独热编码 y_train = tf.keras.utils.to_categorical(y_train) y_test = tf.keras.utils.to_categorical(y_test) ``` 4. 构建模型: ```python model = models.Sequential() model.add(layers.Dense(units=64, activation='relu', input_shape=(input_shape,))) model.add(layers.Dense(units=num_classes, activation='softmax')) model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) ``` 5. 模型训练: ```python model.fit(X_train, y_train, batch_size=batch_size, epochs=epochs, validation_data=(X_test, y_test)) ``` 6. 模型评估: ```python test_loss, test_accuracy = model.evaluate(X_test, y_test) ``` 7. 模型预测: ```python predictions = model.predict(X_test) ``` 这只是一个简单的示例,实际应用中可能涉及到更多的技巧和步骤。深度学习八股文可以作为一个起点,帮助快速入门和理解深度学习的基本流程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值