cockroachdb mysql_CockroachDB学习笔记——[译]CockroachDB中的SQL:映射表中数据到键值存储...

CockroachDB学习笔记——[译]CockroachDB中的SQL:映射表中数据到键值存储

原文标题:SQL in CockroachDB: Mapping Table Data to Key-Value Storage

原作者:Peter Mattis , Tamir Duberstein

原文日期:Sep 16, 2015

译:zifeiy

CockroachDB中的SQL:映射表中数据到键值存储

SQL?我觉得CockroachDB是一个键值存储?!?

在过去,我们将CockroachDB描述成一个分布式的、事物一致性的、键-值存储数据库。

我们知道我们想要提供的并不仅仅是一个键-值模型的API,我们想要设计的是一个更高级的结构化数据API,让他能够支持数据库中的表(table)和索引(index)。

除了支持这样的丰富结构外,我们还期望最终支持SQL来操纵和访问这种结构化数据。

经过一番绞尽脑汁之后,我们排除了所有使用SQL的不可能性,并以SQL作为我们结构化数据层的核心,全速前进。

在一个SQL中有很多组建需要设计,仅仅据一些例子:查询解析(query parsing),查询分析(query analysis),查询规划(query planning),查询执行(query execution),事务(transactions),持久存储(persistent storage)。

CockroachDB的SQL系统建立在内部的CockroachDB 键-值存储之上,并利用整体排序的键值映射来存储所有SQL表数据和索引。

本文将重点讨论CockroachDB在SQL数据和键-值存储中的映射关系,并且展示这种映射如何磅数实现SQL功能。

未来的文章将讨论查询分析、规划和执行。

一个SQL表(table)是由一系列的行(row)组成的,每一行包含若干列(column)。

每一列都有它关联的类型(bool, int, float, string, bytes)。

表还具有关联索引,允许从表中高效地检索行的范围。

这听起来根本不像是一个将字符串映射到字符串的键-值API呀。如何将SQL表映射到K-V(键-值)存储呢?

首先,一个入门:CockroachDB内部的键-值 API支持大量的操作,但是在这篇文章中我们只需要知道其中的一部分:

ConditionalPut(key, value, expected-value) - 如果expect-value对应的条件成立,则我们将value的值赋给key。

Scan(start-key, end-key) - 在区间[start-key,end-key)对应的区间(左闭右开区间)内检索所有的键。

在CockroachDB中,键和值都可以包含不限制字节数的字符串。

Ok!让我们继续!

键编码(Key Encoding)

将SQL表中的数据到键和值的基本问题是将有类型之分的列数据编码为字符串。

比如,给定一组数值<1, 2.3, "four”>,我们会将其编码为一个字符串,而这个字符串看上去像是这样的:

/1/2.3/"four”

我们使用反斜杠作为值之间的视觉分隔符,尽管这仅仅是出于可读性的目的。

我们可以把一篇完整的博客文章献给这些编码。(意思是:说到编码我们可以将一大堆咯,大家就先按照我这么说的理解有可以了)

为了简单起见,这里只讨论了它们的性质,而不是它们的实现。

被编码的键们是排序的,因此键的每一个字段都被认为是分开的:

/1/2.3/"four”

/2/3.1/"six”

/10/4.6/"seven”

如果你按照原始的方法天真的为这些字符串排序,你会发现/10/...是排在/2/...之前的。

编码工作可以变得更神奇一点如果你之前没有碰到过类似情况。

如果你对编码的细节感兴趣可以在util/encoding中查看{Encode,Decode}{Varint,Float,Bytes,Null}。

(译者注:原链接https://github.com/cockroachdb/cockroach/tree/master/util/encoding已失效,译者找到了新的链接https://github.com/cockroachdb/cockroach/tree/master/pkg/util/encoding)

有了这个编码工具,我们就可以窥视SQL表数据的编码。

在CockroachDB中,每个表在创建时都有一个唯一的64位整数ID分配给它。

此表ID用作与该表关联的所有键的前缀。

现在让我们考虑如下的表和数据:

CREATE TABLE test (

key INT PRIMARY KEY,

floatVal FLOAT,

stringVal STRING

)

INSERT INTO test VALUES (10, 4.5, "hello”)

CockroachDB中的每一张表都必须有一个主键。

主键由一个或多个列组成;在上面的测试表中,它由单个列组成。

CockroachDB将每个非主键列存储在由主键作为前缀并且由列名作为后缀的单独密钥中。

因此,行<10, 4.5, "hello">将以如下形式存储在我们的test表中:

Key

Value

/test/10/floatVal

4.5

/test/10/stringVal

"hello”

在这个描述中,我们使用/test/作为表ID(table ID)的占位符,

使用/floatVal/和stringVal作为列ID(column ID)的占位符。

(表中的每个列都具有表中唯一的ID。)

注意,在我们的编码中主键紧跟在表ID(table ID)之后。

这是CockroachDB SQL实现中索引描述(index-scans)的基础。

如果我们揭开现象看本质的话,我们将看到表的元数据如下:

test Table ID

1000

key Column ID

1

floatVal Column ID

2

stringVal Column ID

3

在数字表单中,我们的表的键值对看起来像:

Key

Value

/1000/10/2

4.5

/1000/10/3

"hello”

在这篇文章的剩余部分,我们将以这种符号的形式来描述键。

【你也许会想在每一个键前面都添加一个公共的前缀(/1000/10)太浪费存储空间了,但是我们的底层存储引擎RocksDB,

通过将密钥的前缀压缩几乎消除了所有开销。】

精明的读者会注意到,在主键中存储列的键值对是不必要的,因为这些列的值已经在密钥本身中编码。

事实上,CockroachDB很喜欢这样。

注意,因为主键前缀的缘故,对于某一个特定行的所有列将彼此相邻存储(键和值存储在CockroachDB中的一个已排序的整体映射(Map)中,所以这个属性是免费的)。

这允许使用前缀扫描来检索特定行的值。这正是CockroachDB内部所做的。

查询:

SELECT * FROM test WHERE key = 10

将会被翻译成:

Scan(/test/10/, /test/10/Ω)

这个操作将只会检索行的两个键。

Ω表示最后一个可能的键的后缀。

然后,查询执行引擎将解码密钥以重构行。

空列值(Null Column Values)

这个故事有一个小小的转折:

除非特别指定了NOT NULL,不然列的值时可能为NULL的。

CockroachDB并不使用NULL值,而是使用一对键值对的缺席来标记空值。

细心的同学可能已经看到了这里的一个问题了:按照这种分析,如果一行数据里面的所有非主键的列是NULL的,那么我们将不会存储这组数据了。

为了解决这个问题,CocoroachDB始终为那些有主键但是没有列后缀的行数据添加一个前哨键(sentinal key)。

以行<10, 4.5, "hello”>,他的前哨键将是/test/10。啊哈!

二级索引(Secondary Indexes)

到目前为止,我们忽略了次要索引。让我们纠正这种疏忽:

CREATE INDEX foo ON test (stringVal)

这句SQL在列stringVal上创建了一个二级索引。

我们没有声明索引是唯一的,所以允许重复的值。

类似于表的行,我们将把所有索引数据存储在由表ID作为前缀的键中。

但是我们希望从行数据中分离索引数据。

我们通过引入索引ID来实现这一点,该索引对于表中的每个索引都是唯一的,包括主键索引(对不起,我们之前说谎了!):

/tableID/indexID/indexColumns[/columnID]

我们用上面的例子得到的键稍长一些:

Key

Value

/test/primary/10

Ø

/test/primary/10/floatVal

4.5

/test/primary/10/stringVal

"hello”

并且现在我们对于我们的索引foo也有一个单独的键:

Key

Value

/test/foo/”hello”/10

Ø

您可能想知道为什么我们用主键值(/10)作为这个编码的后缀。

对于像foo样的非唯一索引,这是必要的,以便允许相同的值在多行中发生。

因为根据定义表的主键是唯一的,所以将其作为后缀添加到一个非唯一的键后面将会形成一个唯一的键。

一般而言,对于一个非唯一索引,CockroachDB将包含在主键中但是不包含在索引中的所有列追加到值后面。

现在让我们来看当我们把<4, NULL, "hello”>插入到我们的表中会发生什么:

Key

Value

/test/primary/4

Ø

/test/primary/4/stringVal

"hello”

/test/foo/"hello”/4

Ø

所有的表中的数据合到一起看起来是这样的:

Key

Value

/test/primary/4

Ø

/test/primary/4/stringVal

"hello”

/test/primary/10

Ø

/test/primary/10/floatVal

4.5

/test/primary/10/stringVal

"hello”

/test/foo/"hello”/4

Ø

/test/foo/"hello”/10

Ø

次级索引被用在 SELECT 中用于扫描一组小的集合的键。考虑:

SELECT key FROM test WHERE stringVal = "hello”

这个查询的规划师(query planner)会注意到在StringVal上有一个索引,并将此查询翻译成:

Scan(/test/foo/”hello”/, /test/foo/”hello"/Ω)

它将检索以下的键:

Key

Value

/test/foo/”hello”/4

Ø

/test/foo/”hello”/10

Ø

注意到这些键不仅包括索引列stringVal,而且还包括主键列所对应的键(译者注:4和10)。

CockroachDB将会注意到主键列上的键并且避免对整行数据进行不必要的查找。

最后,让我们看一下如何对唯一索引进行编码。

除了我们早先创建的索引foo,我们在创建一个uniqueFoo:

CREATE UNIQUE INDEX uniqueFoo ON test (stringVal)

与非唯一索引不同,唯一索引的键仅由索引的一部分组成。

键中存储的值是主键组成的列中去除掉索引中的列之后剩下的那些列。

我们的test表中的两行数据将被编码成:

Key

Value

/test/uniqueFoo/"hello”

/4

/test/uniqueFoo/"hello”

/10

我们使用ConditionalPut函数,尝试写入数据之前检测这个键是否早已存在了,已检测是否违反了唯一性约束。

这就是CockroachDB如何简单地将SQL数据映射到键值存储中的方式。

请密切关注接下来关于查询分析(query analysis)、计划(planning)和执行(execution)的文章。

将SQL映射为键值存储的电子并不是在CockroachDB中独有的。这本质上也是MySQL on InnoDB、Sqlite4和其他很多数据库的设计。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/563484.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

kafka topic 目录存放在哪_Kafka系列文章之安装测试-第2篇

前言上篇文章讲解了 Kafka 的基础概念和架构&#xff0c;了解了基本概念之后&#xff0c;必须得实践一波了&#xff0c;所谓“实践才是检验真理的唯一办法”&#xff0c;后续系列关于 Kafka 的文章都以 kafka_2.11-0.9.0.0 为例&#xff1b;另外为了让大家快速入门&#xff0c;…

java开发分支_如何选择Java 的分支?

问题阐述听说Java 无所不能&#xff0c;从简单的手机游戏到世界500 强的官方网站都能开发&#xff0c;作为一名Java 的初学者&#xff0c;我该如何入手&#xff1f;专家解答自诞生之日起&#xff0c;Java 语言就处于不断的发展中。目前&#xff0c;其主要分为以下3 个分支。. J…

蚂蚁爬杆 java_java蚂蚁爬杆

import java.util.List;import java.util.ArrayList;import java.math.BigDecimal;/*-作者:volcano_hosan*-----------蚂蚁爬杆*有一根300厘米的细木杆&#xff0c;在第30厘米、80厘米、110厘米、160厘米、250厘米这五个位置上各有一只蚂蚁。*木杆很细&#xff0c;不能同时通过…

java制作加载界面_Java如何制作启动界面?

展开全部大概的思路就是使用线程来计算耗时的32313133353236313431303231363533e58685e5aeb931333337613133操作&#xff0c;在前段显示启动的窗口&#xff0c;示例如下&#xff1a;java 代码/** To change this template, choose Tools | Templates* and open the template in…

java 生成客户端代码_swagger-codegen生成java客户端代码

前后端分离的时候&#xff0c;需要建立契约&#xff0c;Swagger可达到该目的(略)。建立Rest接口后&#xff0c;通过swagger-codegen项目可以自动生成对应的客户端代码(c、php、java、js、node等等)&#xff0c;关于swagger-codegen项目的使用&#xff0c;发现中文文档较少&…

mysql无法启动修复_记一次MySQL无法启动及修复经历

记得有次本地的MySQL无法启动&#xff0c;网上说&#xff0c;去删掉InnoDB日志就行&#xff0c;我就傻乎乎的去删掉了InnoDB相关的文件&#xff0c;果然&#xff0c;没有任何问题&#xff0c;正常启动了。可是谁曾想&#xff0c;过了几天&#xff0c;故障复现了&#xff0c;我就…

mysql的操作语句_Mysql最常用的操作语句收集

Mysql中常用语句简单易学springboot微服务是现在流行的框架&#xff0c;目前大多数做java的人都在使用&#xff0c;java的生态一直很好&#xff0c;各种插件各种第三方jar包推动着java的运行。Mysql是Springboot最常用的数据库&#xff0c;主要原因是Mysql免费而且轻量。考虑性…

java获取网络带宽_Linux Java 获取CPU使用率,内存使用率,磁盘IO,网络带宽使用率等等...

/*** 获取带宽上传下载速度* return*/public String getNetWorkSpeed() {boolean result false;String detailInfo "";DecimalFormat df new DecimalFormat("0.00");String dl "";String ul "";System.out.println("开始收集…

java周期_java 周期时期计算

package org.apple.date;import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Date;/*** 周期时间* author shaoyu**/public class CycleDate {public static void main(String[] args) {SimpleDateFormat dateformatnew SimpleDateFormat("yy…

python实现qq登录界面_使用Python编写一个QQ办公版的图形登录界面!

最近&#xff0c;QQ的办公版本——TIM进行了一次更新升级。本次更新升级大幅修改了界面的样式&#xff0c;看起来更加的清爽、简洁和高效了。这种界面州的先生还是比较喜欢的&#xff0c;没有QQ那么花里胡哨&#xff0c;也比微信那些残缺的功能更加丰富。并且这次的登录界面还新…

python算法详解豆瓣_豆瓣爬虫实践-python版

豆瓣登录&#xff0c;无验证码版&#xff1a;import requests#starturl "https://www.douban.com/accounts/login"loginurl "https://accounts.douban.com/login"headers {User-Agent:Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KH…

python项目打包部署到ios_Python iOS 自动打包脚本(包含上传到fir)

Python iOS自动打包脚本使用说明1.1 使用python3编写&#xff0c;没有python3 环境的需要下载python3python官网下载1.2 通过Homebrew安装Python31.2.1 先搜索$ brew search python输出&#xff1a;app-engine-python micropython python3boost-python python wxpythongst-pyth…

stlink 升级固件以后失败_ST-Link不能下载程序的几种解决办法

一直在用J-LINK&#xff0c;最近改用ST-Link&#xff0c;出现了不少无法下载程序的情况&#xff0c;这里列出几种解决的办法(针对STM32F103系列)&#xff1a;1#是不是你没有选择Flash算法&#xff1f;什么都没有加的话&#xff0c;会提示“找不到Flash算法”的哦2#是不是你JTAG…

cnsl是什么意思_VS2010下创建静态链接库和动态链接库

VS2010下创建静态链接库和动态链接库类封装成dll如果你的工作长期与某个领域相关&#xff0c;比如说长期做直接体绘制 (DVR)方面的开发&#xff0c;那么你可能经常使用自己的传递函数类&#xff0c;如果每一个工程你都把传递函数类的.h和.cpp文件添加进去会比较麻烦&#xff0c…

java hash取余_为什么Java的hash表的长度一直是2的指数次幂?为什么这个(hash(h-1)=hash%h)位运算公式等价于取余运算?...

1.什么是hash表&#xff1f;答&#xff1a;简单回答散列表&#xff0c;在hash结构散列(分散)存放的一种数据集结构。2.如何散列排布&#xff0c;如何均匀排布&#xff1f;答&#xff1a;取余运算3.Java中如何实现&#xff1f;答&#xff1a;hash&(h-1)4.为什么hash&(h-…

java .net 3des_Java.net3DES差异及互通

主要差异如下&#xff1a;1、 对于待加密解密的数据&#xff0c;各自的填充模式不一样C#的模式有&#xff1a;ANSIX923、ISO10126、None、PKCS7、Zero&#xff0c;而Java有&#xff1a;NoPadding、PKCS5Padding、SSL3Padding2、 各自默认的3DES实现&#xff0c;模式和填充方式…

生产调度java程序原码_Rxjava的线程调度源码解析

代码调用Observable.just(1).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer() {Overridepublic void accept(Integer integer) throws Exception {}});直接进入主题&#xff0c;先看subscribe中调用了哪些方法//Observable.…

linux 触摸屏测试源码_Linux触摸屏驱动

问题二&#xff1a;echo "ac_cv_func_malloc_0_nonnullyes" >arm-linux.cache//避免检查ac_cv_func_malloc_0_nonnull若出现提示: undefined reference to rpl_malloc解决&#xff1a;发现config.h.in和config.h里定义了#undef malloc#undef realloc把这两个用//注…

java有没有number数据类型_Java基本数据类型之Number

数据类型byte&#xff1a;byte数据类型是8位、有符号的&#xff0c;以二进制补码表示的整数&#xff1b;最小值是-128(-2^7)&#xff1b;最大值是127(2^7-1)&#xff1b;byte类型用在大型数组中节约空间&#xff0c;主要代替整数&#xff0c;因为byte变量占用的空间只有int类型…

java中main缺少主体_缺少方法主体,或声明了摘要

我收到此错误消息&#xff1a;线程“主”中的异常java.lang.RuntimeException&#xff1a;无法编译的源代码-错误的符号类型&#xff1a;PetTest.main(PetTest.java:18)上的Pet.saySomething Java结果&#xff1a;1这是我所拥有的&#xff1a;对于Speak课堂&#xff0c;public …