简单生活

  • 在上周,SQL Server 2022版本(16.x)正式进入公测状态,大家都可以下载并安装了。当前只支持Windows,被称为CTP 2.0版本(community technology preview ),包含了企业版的所有功能,可以试用180天。于是第一时间下载并进行了体验,一起来看看,新版本有哪些新的功能吧。

    01 全面支持与Azure云建立链接

    SQL Server 2022版本在复制与容灾、分析增强、S3存储兼容支持、Azure Arc、Azure Defender等方面,全面的与Azure云在建立链接。

    通过Azure Synapse Link for SQL(公测支持将SQL Server 2022版本与云端Azure Synapse Analytics无缝集成,从而实现分析、BI和ML等数据处理能力。还可以通过Azure SQL Managed Instance的Link功能,实现将云端实例作为本地SQL Server的副本,提供只读或者容灾使用。

    SQL Server安装时,可以直接安装Azure Arc agent;支持使用Azure AD进行数据库的认证;支持使用Azure Defender for SQL来保护SQL Server。

    支持了S3-协议的对象存储:从2012版本开始,已经支持了备份到Azure Blob Storage,2022版本开始支持到S3兼容的存储进行备份;同时,通过,PolyBase功能可以支持S3兼容存储的访问,支持使用T-SQL直接访问parquet文件的数据。

    02新增了账本数据库(ledger database)功能

    2022版本中,新增支持了ledger database功能,提供数据不可篡改的证明。其模式类似于AWS QLDB。具体的,在数据库所有记录的变更都通过递归哈希的Merkle tree记录(被称为Database digests),用户可以通过其他独立的存储保存该Database digests,独立存储可以使用Azure Blob Storage或其他写入后不可修改的存储中。在重要的审计、第三方商务流程记录等场景下,可以使用账本数据库对数据进行不可篡改的存储。

    03 持续提升数据库性能

    • 备节点上支持与主节点上一样的Query Store功能,帮助用户管理与诊断Query的执行计划相关的问题
    • 开始支持Query Store hints功能(注:之前仅Azure云端版本支持)
    • 增强了Memory Grant Feedback (MGF) 功能
    • 提升了大内存场景下的内存管理能力,避免OOM发生;提供了大内存场景下,内存池并行扫描的能力
    • 提供了参数-自感知缓存执行计划能力,帮助SQL Server自动化的处理由于参数分布带来的无法使用最优执行计划的问题
    • 创建表语句新增了XML_COMPRESSION选项,提供XML压缩能力
    • 提供新的硬件感知和使用能力,例如使用高级向量扩展指令集(Advanced Vector Extensions)
    • DOP功能提供新的参数DOP_FEEDBACK,帮助更加自动化管理DOP参数的配置
    • 提供了Cardinality estimation feedback,帮助定位由于基数预估不准确导致的性能问题
    • 提供了基于Query Store功能的强制执行计划选择能力

    04 持续增强可用性与可管理性

    • 提供了”contained availability group”,在AG层面提供了自己的元数据管理、并且包含了需要的一些系统数据库等内容
    • 支持了AG参数REQUIRED_SYNCHRONIZED_SECONDARIES_TO_COMMIT的修改
    • 在SQL Server初始安装时,可以直接安装Azure Arc agent
    • 进一步优化了ADR功能(Accelerated Database Recovery),开启后数据库在异常恢复时能够更快,提升整体可用性
    • 提升快照备份能力,新增了使用T-SQL冻结IO操作
    • 新增参数降低数据库收缩(空间回收)是对数据库并发读写的影响
    • 新增了数据库级别变量实现异步的统计信息更新,以降低对数据库并发读写的影响
    • 支持数据备份到S3兼容的存储中,也可以直接从这类存储中恢复数据

    05 增强了数据库安全

    • 支持使用Azure Defender for SQL保护SQL Server
    • 基于最小权限原则,对于某些管理任务新增了新的内置权限与角色
    • 提供了更细粒度(包括database、schema、table或column级别)的UNMASK权限管理
    • 更好的支持了对秘钥(数字证书和秘钥)向Azure Blob Storage的备份
    • 支持新的TDS 8.0协议,兼容TLS 1.3
    • 增强了Always encrypted数据的加密查询能力,包括 JOIN, GROUP BY, and ORDER BY等

    06 其他功能与细节方面的增强

    • 新增更多的JSON相关的函数:ISJSON、JSON_ARRAY、JSON_OBJECT、JSON_PATH_EXISTS等
    • 新增了部分处理时序数据的函数,例如DATE_BUCKET、GENERATE_SERIES等
    • 新增SELECT…WINDOW语法
    • ALTER TABLE ADD CONSTRAINT支持中断后续执行
    • 新增部分聚合和字符处理函数:GREATEST、LEAST、STRING_SPLIT
    • Azure Data Studio、VS Code最新版本都开始支持SQL Server 2022;SSMS发布最新的19.0版本;

    总结在2022版本中,继续增加了性能、安全性、可管理性,最重要就是增强了与Azure云的联系,帮助用户用好本地数据库的同时,具备较为便捷的向Azure云端迁移的能力。相关参考阅读:

    > What’s new in SQL Server 2022 (16.x) Preview :

    https://docs.microsoft.com/en-us/sql/sql-server/what-s-new-in-sql-server-2022?view=sql-server-ver16

    > Get SQL Server 2022 Preview Evaluation Edition

    https://go.microsoft.com/fwlink/?linkid=2162126

  • 在上周的Google I/O大会上,GCP(Google云平台)正式对外发布了数据库AlloyDB(Preview版本)。这里对AlloyDB的架构也做一个较为深入的分析,看看与当前的云原生数据库PolarDB、Aurora有哪些异同。

    01 AlloyDB 整体架构图

    AlloyDB是GCP上的一个全托管的云数据库服务,当前完全兼容PostgreSQL 14,提供企业级的性能、扩展性与可用性。声称是标准PostgreSQL性能的4倍,AWS同类服务的两倍(应该是指RDS PostgreSQL和Aurora PostgreSQL),如果是分析查询,则可能有100倍的性能加速。另外,在介绍时,还特别提到,价格非常透明,这应该是针对当前AWS数据库大多数都对IOPS独立并按量计费而说的。

    根据当前资料,其整体架构如下:

    高清大图下载地址:

    https://cloud-database-tech.github.io/images/alloydb-arch-with-qr-code.png

    02 AlloyDB与Aurora、PolarDB有什么异同

    • 简单来说,其架构与现有的云原生数据库Aurora、PolarDB都非常相似。使用了存储计算分离,分布式存储提供了多节点挂载能力。分布式存储,会带来海量存储能力,以及非常强的IO吞吐能力;多点挂载,大大增强了数据库的读扩展能力,同时因为底层使用同一个存储,所以也不再有数据拷贝和延迟等问题。
    • 在实现上,体现了”the log is the database”,尽可能只传输日志,避免数据块的传输与复制。例如,计算节点与存储节点的不再传输数据块(当然,就多了一个日志应用的过程)。这一点与Aurora类似,但是PolarDB在日志下推上,做得比较少,而是选择将存储以”较为标准”的文件系统提供给计算节点,数据库本身的各个模块还是比较完整的,这带来的好处是,对数据库的侵入要稍微小一些,对于新版本的支持和不同的数据库的支持会更加简单和一致。Aurora和AlloyDB的这种做法,则是将数据库的解构更加彻底,将数据库的日志模块一定程度下沉到存储层。在AlloyDB在实现时,还将这个部分彻底的做了分布式,通过多个不同的日志处理进程(LPS)进行分布式并发处理。
    • 这种日志处理的下推,也让数据库在进行崩溃恢复的时候,相比传统的一体化架构要快非常多,也就让数据库所提供的SLA可以更高。因为没有checkpoint,也应该就没有什么fuzzy或者sharp一说了,后端的LPS进程会持续的将redo apply到本地存储,分布式存储上的数据块的版本总是非常新的。而不用像传统数据库,数据库crash后,所有的没有刷写到磁盘的脏数据块(内存中该数据库已经更新,但是还没有刷写到磁盘)都需要通过redo应用到最新状态,所以,传统数据库在崩溃恢复时总是需要一定的时间,而且内存越大,这个时间可能会越长。
    • 另外,AlloyDB的日志存储使用了较为独立的存储,也就是文中提到了”log storage”或者”log store”。考虑日志与数据块的读写特性都不相同,使用独立的存储在性能优化上,会更加有效。一般来说,日志写入通常是append-only的,而且是”同步”操作,需要非常低的延迟,另外,在AlloyDB的设计中,日志写入后,需要立刻读取并应用到数据块中。只需要将内存中已经更新过的数据块覆盖写入本地存储就可以了。而数据块的处理,通常来说是一个异步的过程(不阻塞数据库的写入),并且会有大量的随机读,这与日志数据的访问有很大的不同。这里的一个猜测是,日志存储和数据块存储可能使用同一套存储架构,但是可能使用面向不同场景的优化和参数,如果有Google的人,希望求证一下。
    • 计算节点使用了”ultra-fast cache”,猜测一下,可能是使用了与PolarDB类似的optane存储作为加速,虽然使用optane卡的场景不同。这也是另一个希望求证的点。
    • AlloyDB的数据块请求是带有LSN号的,而每个可用区(Zone)内都有完整的数据块,所以,在各个可用区的节点(可能是read replica)总是可以在本地可用区获得最新的数据块。也就是无需像Aurora使用的多数派协议,数据块的读取需要3份(写入四份,4+3>6),当然Aurora也对这里做了很多的优化(例如,通过一个bookkeeping记录写入数据和node的对应关系,尽可能将多数派读取变成一次单节点的读取[参考])。
    • AlloyDB下沉到存储的日志处理服务(LPS),也做了彻底的分布式。日志存储在一个底层的相对独立的日志存储中,日志处理服务则是一个分布式的、相对”无状态”的进程,因为也做了存算分离,所以有非常好的扩展性。另外,在日志处理的分片上,AlloyDB通过将底层的数据块分成一个个独立的分片(Shard,应该类似于PolarDB或其他系统中的chunk),每个分片由一个独立的LPS处理,一个LPS可以根据系统压力情况处理一个或多个分片。这样就通过分布式的方式解决了日志应用的问题。并且,这个日志应用是在各个不同的可用区独立运行。
    • 关于数据副本数量的问题:Aurora是3*2的副本设计,每个可用区两个副本,每次写入应该是3个副本,读取可能需要4个副本,这种性能应该比较差,达到的效果是宣传”AZ+1”的容灾能力,也就是一个可用区失败,再加一个副本失败,依旧可以恢复数据。在实现上,Aurora对于底层副本感知是要更强的,并与上层实现结合起来了。但是AlloyDB使用Google底层统一的存储,这里看到的数据分布在三个zone,有三个副本,但实际上,每个zone的数据是存储在一个分布式存储的,这个分布式存储数据的副本数情况,并没有对数据库暴露。这里可以猜测,可能是两个副本或者更多,对于数据库这里IO敏感型的应用,应该比较难使用EC算法去做去重。所以,实际上,一份数据,可能会有超过6份的副本数。
    • 另外,这里看到,Block storage部分是可以通过一些智能化的方式,对数据块进行分级,降低整体的存储成本的,这应该是底层存储的数据分层能力。

    03 AlloyDB的写操作

    这里通过一个写操作来看看,AlloyDB的整个处理流程。客户端通过TCP连接,连接到主实例,然后将变更SQL发送到主实例。主节点进行SQL解析、并在内容中更新数据和索引页,同时,准备好WAL日志。在事务提交时,则同步地将日志写入低延迟的日志存储,这些日志则会被日志处理进程(LPS)异步的消费并处理。

    存储层被分成了三个部分:日志存储、日志处理服务、数据块存储。日志存储本身是顺序写,并对写入延迟要求很高,会直接影响事务处理的性能。AlloyDB专门针对该模式/场景进行了优化,以提供一个高性能的、低延迟的日志存储服务。

    多个日志处理服务(LPS)则会根据”Shard”(一组数据库的数据块)机制,对不同的日志进行处理。先从存储层读取需要处理的数据块(随机读),然后将redo日志应用到这些数据块,并回写(持久化)数据块到存储中,并最终删除日志存储中的日志记录。

    04 AlloyDB的读操作

    读操作有两种情况,一个是从主节点提供服务,一个是从读节点(read replica)提供服务。如果查询所需要的数据都在内存中,那么就和单机的PostgreSQL实例一样,进行SQL解析、执行计划生成、查询执行,并响应用户。为了加速查询处理,AlloyDB在数据库中额外集成了一个”ultra-fast block cache”。

    如果,需要的数据块在上面的两级缓存中都不存在,则需要到存储中获取。在把请求发送给存储层的时候,需要附带把LSN(log-sequence number)号也作为请求的一部分,而底层存储则返回满足该LSN对应事务能够看到数据块。

    从整体存储层来看,LPS进程也会参与数据块的请求的处理。LPS进程也有自己的缓存,如果请求的数据块在这个缓存中,则会立刻返回给上层节点。如果,这里再次缓存缺失,则再向数据块存储读取数据块并响应请求。

    这里,LPS进程需要存储一个”列表”,用于记录日志已经提交,但是,还没有应用到底层的块记录。对于此类数据块的请求,则需要先完成日志应用再返回。虽然,此类情况不应该经常出现,因为如果是一个最近日志没有应用的块,缓存应该不太会把这样的页面清除。

    05 其他

    • 虽然是Preview,但已经是目前看到的最具诚意的Preview了:任何用户立刻就可以开通使用,并且给予了非常大的免费额度,具体的,计算节点每月免费不超过1.5万美元、存储节点不超过650美元的资源。
    • 另外,注意到,GCP会说这是一个”fully-managed, PostgreSQL-compatible database”,而不会过多的强调这是一个云原生的数据库系统。对于用户来说,这就是一个具备高性能、高可用以及高可靠的PostgreSQL。至于,是不是Cloud-Native的,Google似乎对于这个概念并不那么”感冒”。
    • 通过实现”non-disruptive instance resizing”、Vacuum优化管理、Crash Recovery的速度提升,这个服务推出就是99.99%的SLA。
    • 更底层使用的是Google内部统一的分布式存储层,经过Gmail、Youtube等大型系统的验证,性能/稳定性等经过了验证。这一点上,AlloyDB与PolarDB、Aurora是不一样的。PolarDB和Aurora都选择了实现自己面向数据库的分布式存储系统,而AlloyDB选择了更加通用的存储层,再面向数据库进行优化。这两个路线,客户价值都是直接的,但哪个方案的生命力会更加持久,可能需要几十年的时间去观察。
    • 与AlloyDB一起,GCP还推出一个Oracle到PostgreSQL的迁移服务,只是这个服务看起来推出的也比较仓促,比较困难的结构迁移部分,使用了一个第三方的开源产品来实现。一方面可以看到这个,迁移是非常重要的模块,另一方面也看到,这一块做起来其实比较难。从这里看到,AlloyDB考虑优先推出PostgreSQL版本的一个重要原因,是认为:Oracle数据库的迁移至关重要,且PostgreSQL是Oracle迁移的重要目标数据库。
    • 目前,发布的内容来看,关于数据库内部的并发访问/多版本管理的内容比较少,这部分应该是另一个复杂的点。期待后续的文章。

    06 一些已知的不确定的点

    • ultra-fast cache是什么介质?如何被使用?
    • 对于其他zone(非primary节点所在的zone),他的WAL日志(在log storage上)从哪里获取?WAL一定是具备跨zone的容灾能力的,这里WAL的容灾是在数据层去做的(日志写时写两份或者三份),还是log storage去做的?
    • 与上面的问题相关的另一个重要的问题,LPS进程是全局的还是属于某个Zone的?
    • log storage是针对日志场景专门进行优化的,其模式是,append-only、延迟敏感并直接影响效率,这里的疑问是,做了哪些优化?

    如果有Google的同学,可以一起讨论一下。

    参考

    • AlloyDB for PostgreSQL under the hood: Intelligent, database-aware storage
    • AlloyDB for PostgreSQL
    • Introducing AlloyDB for PostgreSQL: Free yourself from expensive, legacy databases
  • 实测阿里云RDS Serverless

    ·

    在4月底,阿里云RDS Serverless正式公测发布。第一时间申请了公测资格,并进行了测试验证。测试完成后,还是非常期待这个功能的商业化的,当前的公测版本也值得开发者们去了解和小范围(例如开发测试环境)尝试。

    00 什么是RDS Serverless

    RDS Serverless是一种独立于按量付费、包年包月的资源使用与计费模式。提供了一种自动化的弹性扩缩容的规格,用户无需提前选定固定规格,后端会根据系统压力进行自动升降配,并根据实际使用计费,当然,用户需要设置该规格最大和最小规格,限制最大、最小使用资源与费用。

    对于峰谷明显的业务系统,该模式一方面可以在需要时提供很高的资源规格应对压力,另一方面可以在低峰时降低资源使用,降低成本。

    01测试结论概述

    • 整体上,该Serverless版本的升/降配速度非常快,约10秒完成压力检测与变配,升配时性能表现非常平稳,降配时性能比较平稳。
    • 具体的,在系统压力突增时,约10秒内就可以完成检测与变配,完成升配后系统压力立刻得到一定程度的缓解;与之前的Aurora Serverless v2测试中,升配的时间是差不多的,都是10秒以内
    • 在系统压力下降时,降配的速度也非常快,约10秒完成检测与降配操作。另外,需要注意的是,当前的版本,因为降配非常快,也导致降配后,性能出现了一些波动,持续约10秒,波动幅度从约8毫秒的响应时间增长到30~50毫秒,在两次降配之后,都出现这样小波动。相比,Aurora降配更加“保守”,观测了50秒,之后才开始降配。在降配之后,Aurora的性能依旧非常平稳,没有任何波动。也就是说,降配过程中清除出内存池的数据页都是确确实实不再使用的,这里可能需要深入的观测InnoDB的Buffer Pool收缩时的表现,避免将可能使用数据页清理出内存。
    • 目前只支持基础版(单节点实例),应用场景还比较有限,不过对于开发测试环境,种类可用性要求没那么高,且性能峰谷明显的场景,是可以轻松节省超过50%成本的,而且在实际使用时,性能还会非常不错(最高扩展到8*RCU)。
    • 当然,现在阿里云RDS Serverless还是刚刚公测,申请公测资格通过后,可免费创建2个体验实例,最大规格为8*RCU,即约8c16g内存的实例,免费周期3个月,算是不错的羊毛了,具体的,可以通过RDS MySQL购买页找到公测申请链接。

    02 测试方法说明

    整体的测试方法与之前做Aurora Serverless v2类似。首先,启动一个单线程sysbench,作为测试“主进程”,程序运行900秒,在“主进程”运行300秒后,再启动一个“压力进程”(24并发的sysbench进程)向系统施压,该进程运行300秒后退出,在这个过程中,我们观测”主进程”的rt变化,以及整个过程中,实例规格的变化(依旧以buffer pool为指标)。更详细的描述可以参考:实测Aurora Serverless v2

    03 测试结果与分析

    3.1 整体过程

    • 下图黄点代表主进程每秒RT的变化;”蓝点”(连成线)代表秒级别buffer pool的变化。左侧纵坐标为响应时间,单位为毫秒;右边纵坐标为buffer pool大小,单位为GB
    • 在第300秒,“压力进程”给出额外压力之后,系统开始升配,经过三次升配之后,到最大规格
    • 在第600秒,“压力进程”退出,经过了4次降配,降级到最低规格

    3.2 升配过程

    从如下放大的图可以看到,在“压力线程”启动的第300秒,“主线程”的响应时间立刻增长到了300ms。

    • 该实例在之后的7秒内完成升配,实例响应时间也立刻降了下来,降到约75毫秒
    • 之后,再过10秒(约第317秒),完成了第二次升配,实例响应时间再次下降,约到30毫秒
    • 再过约10秒(约第328秒),再次升配,但是此时响应时间不再有什么变化

    3.3 降配过程

    • 第600秒,压力进程退出,约11秒后,完成降配。但是,在第15秒性能出现明显波动,持续10秒
    • 第650秒,完成第二次降配,4秒后性能出现波动,持续约5秒
    • 第670秒,再次降配,性能再次波动,并出现一个异常点,响应时间非常大(约200ms)
    • 之后,系统平稳运行

    04 其他

    • 当前RDS Serverless处于公测阶段,没有SLA保障,且仅支持基础版、区域支持也有限,虽然降配和升配都比较快,也比较稳定,但是还不适合生产环境。
    • 当前,实例规格区间为0.5~8 RCU,最大规格也还比较小。
    • 在这次对比测试中,也发现,相比AWS,阿里云在同一个可用区的网络延迟是更低的,仅5~10ms,而Aurora同可用区响应时间约为15~20ms。
    • 据了解,阿里云今年还是会在这个方向加大投入,还会有一些大的版本和改进发出来,拭目以待吧。

  • 实测Aurora Serverless v2

    ·

    Aurora自2014年发布以来,一直是AWS的最核心数据库产品,而Serverless则是这个产品最重要的功能之一了。在2018年08月,Serverless功能刚刚GA,当时做过一次测试(参考)。在2020年底的re:Invent上,Andy Jassy宣布Aurora发布Serverless v2,时隔一年半,终于GA,一起来看看实际效果怎样吧。

    在最近看到该功能的介绍文章中,使用了”几分之一秒内扩展”、” scales instantly and nondisruptively “等描述,对此,我是保持怀疑的,这也要实测一下的原因,从一个用户感受的角度,看看一次升级(scaling)需要多长时间。

    测试结果概述

    • 在这次实际测试中,新的Serverless v2,可以将scaling up的时间降低到10秒级别。系统压力上来后,首次升级(scaling up)花了13秒,之后的几次升级分别花了7秒、4秒、10秒等。在这几秒内,Aurora需要完成监控采集、分析与决策,变配动作完成等动作。于用户侧,系统压力突增时,10秒内Aurora就会完成升级,这是非常实用和强大的。
    • 相比4年前GA版本数分钟级别的升级(scaling),新的版本提升非常大。不过,与宣传的亚秒级( in a fraction of a second )还有差距的。当然,一种猜测是,”亚秒内”完成的是变配动作本身,不包括监控、决策与命令下发等过程。
    • Scaling down是逐步阶梯式完成的,每次间隔约1分钟,这是符合预期的。
    • 新的版本与旧版本有非常好的兼容性,可以作为旧版本的replica,然后切换为主节点,也就可以完成平滑的升级。新的版本,支持MySQL 8.0和PostgreSQL 13版本。
    • 该功能的客户价值是非常明显的:在更多的业务场景中,可以帮助用户降低成本,同时也可以帮助应对更多的突发流量。另外,云计算的”使命”之一是通过统一的底层资源调度,提升资源利用率,降低资源使用成本,而该功能,在交易数据库的场景,把这个”使命”的粒度降低到了”秒”级别。用好了该功能,在很多场景中,降低50%的数据库成本应该是容易的。
    (more…)
  • 去年11月,Amazon RDS推出的新的形态:Multi-AZ Cluster(三可用区三节点)。相比“原来的多AZ”(两个可用区)架构,新的Cluster模式是三节点架构,提供了更低的事务延迟,同时有更好的读扩展能力。国内的云厂商中,阿里云和腾讯云很早就有了三节点形态,一起看看,他们有哪些异同,在实际的业务场景中,哪些情况可以选择这种形态。

    AWS RDS三节点(Multi-AZ Cluster)是什么?

    这里将其主要特点概括如下:

    • 这是一种3*AZ部署模式,而原来的Multi-AZ是2AZ部署或者单AZ部署。
    • 使用了数据库的逻辑复制,而原来的双AZ使用的是EBS层的复制,这就使得Cluster的副本节点都可以直接提供读能力,有更好的读扩展能力。
    • 使用了类似MySQL半同步的复制技术,事务日志网络到达其中任意一个副本主节点事务就可以提交,所以主节点上的事务延迟会降低,性能会提升(对比基于EBS的两节点)。
    • 支持Graviton 2的规格和NVMe-based SSD存储,可以提供更好的性能。
    • 同时支持MySQL和PostgreSQL两个引擎。

    与阿里云、腾讯云数据库三节点的区别

    阿里云RDS提供的“三节点企业版”,支持MySQL引擎,通过Paxos协议(或其变种)同步。相比Amazon的方案,其中一个节点使用了日志存储,成本可以更低;三个节点,只有一个节点提供服务。腾讯云MySQL也支持三节点版本,使用了半同步复制,可以选择异步、半同步或者强同步三种模式,也只有一个节点可以提供服务。

    相比AWS,阿里云与腾讯云的三节点模式都可以由用户自由选择可用区分布,即可以都在一个可用区,也可以分布在两个或三个可用区,给了客户更强的灵活性。

    (more…)
  • SQL Server的用户体系和MySQL有非常大的不同,无论是在使用上、还是概念上。所以,这里梳理一下SQL Server的用户与认证的一些基础概念与使用。另外,这个概念在SQL Server相关资料中各个地方都会出现,是理解权限体系的基础。

    “login”“database user”

    在SQL Server中,”login”不是一个动词,而是一个”名称”(注:”log in”是动词),代表的是一个用于登录的对象(Object),这是一个服务器级别的对象,所以,它有自己的登录名(login name)、密码、默认语言、认证方式等。需要强调的是,它不是一个数据库(database)级别的对象。

    而”Database User”是一个数据库级别的对象,与之相对应的则是数据库级别的权限。”Database User”并不能连接或者登录SQL Server实例,所以,一般来说,也不需要密码。

    “login”因为是Server级别的,所以权限也都是Server级别的。本身不能赋予任何数据库相关的权限,但是,login可以和一个Database User建立映射,使用该login连接数据库的时候,该连接也就可以根据Database User权限进行相关的操作了。

    最常见、最简单的创建login和database user的命令如下:

      use zzxdb2;
      create table t_1(id int,nick nchar(12),birthday date);
    
      create login zzxdb2 with password='zzxdb2' ,CHECK_POLICY=OFF;
      create user zzxdb2 for login zzxdb2;
    
      -- 当没有赋予权限的时候,zzxdb2可以登录SQL Server,但是看不到zzxdb2下面的TABLE
      -- 所以,最后还需要赋予database user相应的权限,如下
      exec sp_addrolemember 'db_owner', 'zzxdb2'; 

    为什么容易混淆

    通常的系统中只有用户的概念,权限系统都是基于用户。而SQL Server在其上新增了Login这一层,与其他的系统都不同。另外,在一般的客户端中,在需要登录的时候,通常都是使用”user name”/”password”作为登录认证的凭证,而不是”Login”/”password”,所以初学者通常容易混淆,例如微软的Mac客户端Azure Data Studio:

    一些可以帮助理解”login”和”user”关系的一些问题

    1. 只创建login,而不map到一个具体的database用户,是否可以登录?

    答案是简单的:可以登录,但是没有数据库相关的权限。测试如下:

    先创建一个没有映射到”user”的”login”:

    CREATE LOGIN alogin WITH PASSWORD = 'alogin', CHECK_POLICY=OFF;
    -- 注: CHECK_POLICY可以让你设置简单密码,并不建议加上
    • 使用上面的”login”在Azure Data Studio中连接并进入SQL Server。可以看到,可以正常登录,但是因为没有database相关的权限,所以展示database里面的对象的时候,会失败,如下:

    也就说,”login”只有在与具体的某个database user建立了mapping之后,才可以访问对应的数据库。在上面例子中的”login”主体”alogin”,要访问和管理数据库9zcloud,是会失败的。

    当然,如果真的需要访问的话,那么我们需要先建一个database user,并在user和login之间建立mapping,具体操作如下:

    CREATE USER a_db_user_9zcloud FOR LOGIN alogin;  

    2. 创建用户,不映射到任何login,后续是否还可以重新映射?

    如果在用户创建的时候显式的声明,不映射到任何login,那么后续是否还可以重新映射到某个login?答案似乎没有那么明显了。遂测试如下:

    CREATE USER a_db_user_9zcloud WITHOUT LOGIN;
    ALTER USER  a_db_user_9zcloud WITH LOGIN='alogin';
    -- 报错如下:
    
    消息 33016,级别 16,状态 1,第 45 行
    The user cannot be remapped to a login. Remapping can only be done for users that were mapped to Windows or SQL logins.

    可见,如果在创建的时候显示声明不映射到任何”login”,那么就不能够再重新映射任何的”login”。

    3. 如果用户名和login主体名字不一样,客户端登录的时候使用哪个?

    答案是显然的,但是还是验证一下。

    具体的,如果数据库用户名和login用户名不一样,那么在登录连接SQL Server的时候,使用的是database user还是login的名称?具体看下面的例子,在使用客户端登录的时候,使用的alogin,还是使用a_db_user_9zcloud?

    CREATE LOGIN alogin WITH PASSWORD = 'alogin', CHECK_POLICY=OFF;
    CREATE USER a_db_user_9zcloud FOR LOGIN alogin;

    答案,当然是使用login的主体alogin。

    4. 在创建用户时如果映射到了某个login,同时也创建密码,那么这个密码有什么用?

    是啊,有什么用呢? 具体的,在创建用户时映射到某个具体的login,但是依旧指定一个密码,那么这个密码有什么用?测试验证如下:

    CREATE LOGIN alogin WITH PASSWORD = 'alogin', CHECK_POLICY=OFF;
    CREATE USER a_db_user_9zcloud FOR LOGIN alogin WITH PASSWORD = 'dbuser9zcloud';

    答案:你就不能这么用!!(注:仅当在contained database中可以使用密码,参考) 在明确映射到某个具体的login的用户,不需要密码,也无法指定密码。所以,上面的语句执行会失败,报如下错误:

    消息 33234,级别 16,状态 1,第 47 行
    
    The parameter PASSWORD cannot be provided for users that cannot authenticate in a database.

    另外,注意到login在创建的时候,是可以指定默认数据库(DEFAULT_DATABASE)的;创建用户的时候,可以指定默认的schema。

    其他内容

    • 在给一个对象(主体)赋权的时候,可以通过按照细粒度(某个表的某种权限)方式进行,也可以直接将其加入到某个角色组,那么这个角色组对应的权限就都有了。例如,将login加入到”sysadmin”(fixed server role),那么就有了所有sysadmin角色组的权限,sysadmin可以理解是一个超级权限组,如果在该组中,那么访问对象时不需要检查该账号的权限;与sysadmin对应的一个权限是”CONTROL SERVER”,如果使用GRANT则可以使用这个权限。
    • 另外,前文中偶尔会用到”主体”这个名称,英文对应SQL Server文档中的”Principals”,”主体”是SQL Server官方中文文档的翻译(参考)。可以理解为一个实体,或者前面对象的实例化或者实体,也就是说,某个具体的”server roles, logins, database roles, or users.” 都可以称作”Principals”。
    • SQL Server中的系统表sys.server_principals、sys.server_permissions会存储相关的元数据。
    • 在SQL Server官方文档中将”login”翻译为”登录名”(参考)。这也是为什么,一些客户端在让输入用户名的时候,其实是输入一个login主体名和对应的密码。
    • 在创建user的时候,如果没有显示的指定FOR LOGIN,没有指定WITHOUT LOGIN,那么该user将会被映射到同名的login上(还没有验证这一点,参考:If FOR LOGIN is omitted, the new database user will be mapped to the SQL Server login with the same name.)。
    • 另外,系统中还有一个名字为guest的login,默认是不可用的。
    • 在实际中,也有一些场景是需要创建user,而不映射到任何的login,后续会再考虑介绍这类场景。

    参考阅读

    • Determining Effective Database Engine Permissions:链接 如何查看系统中的账号权限
    • Database Engine Permissions SQL Server 2017 and Azure SQL Database: 链接