SQL Server 2012:SQL Server体系结构——一个查询的生命周期(第2部分)

本文涉及的产品
云数据库 RDS SQL Server,基础系列 2核4GB
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
简介:

计划缓存(Plan Cache)

如果SQL Server已经找到一个好的方式去执行一段代码时,应该把它作为随后的请求重用,因为生成执行计划是耗费时间且资源密集的,这样做是有有意义的。

如果没找到被缓存的计划,然后命令分析器(Command Parser)在T-SQL基础上生成一个查询树(query tree)。查询树(query tree)的内部结构是通过树上的每个结点代表查询中需要的执行操作。这个树然后被传给查询优化器(Query Optimizer)去处理。我们的简单查询没有一个存在的计划,因此一个查询树(query tree)会被创建,然后传给查询优化器(Query Optimizer)。

 

上图展示了命令分析器(Command Parser)是用来检查现存执行计划的计划缓存(plan cache),因为在缓存里没找到我们查询的任何信息,还有从命令分析器(Command Parser)输出传给优化器的查询树(query tree)。

查询优化器(Query Optimizer)是被SQL Server团队视为最有价值的财产,也是产品中最复杂、机密的部分之一。幸运的是,只有底层的算法和源代码被很好保护(即使在微软内部),优化器如何工作才能被研究和监视。

这个所谓的基于成本(cost-based)的优化器,意味要去评估执行查询的各种方式,然后选择被认为拥有最小成本的方式去执行。执行方式以查询计划(query plan)实现并从查询优化器(Query Optimizer)输出。

基于刚才的介绍,你认为优化器的工作是找到最好的查询计划会被原谅的,因为那看起来是很明显的设想。然而它的实际工作是在一段时间内找到好的计划,而不是最佳计划。优化器的目标通常被描述为找最有效率的计划。

如果优化器每次都尝试去找最好的计划,比起执行一个慢的计划,找个最好的计划花费的时间更长(一些内建的试探法实际上在保证优化器从不花更长的时间找到好计划,而是就找一个计划并执行它)。

优化器同样在成本的基础执行多级优化,在每一阶段增加更多可用选择项来找更好的计划。当一个好计划被找到时,优化器就停在那一阶段了。

第1阶段被称之为预优化,当语句是足够简单而只有一个最佳计划时,在第一阶段就退出剩下的步骤,移除额外成本需要。没有join的基本查询被认为简单,计划成本产出为0,然后被提及为普通计划(trivial plans)。

优化实际上开始的下一阶段包含三个查找时期:

  • 第0时期——这个时期优化器会找内循环连接(nested loop joins)且不考虑并行运算符(parallel operators)。

如果已经找到的计划成本小于0.2,优化器会停在这里。在这个阶段生成的计划称为事务处理(transaction processing)或简称TP计划。

  • 第1时期——第1时期使用可用优化规则的子集来找常用格式(common patterns)的已有计划。

如果已经知道的计划成本小于1.0,优化器会停在这里。这个阶段生成的计划被称为快速计划(quick plans)。

  • 第2时期——在这个最后时期优化器全力以赴(pulls out all the stops)使用它所有的优化规则。它同样也会找下并行(parallelism)和索引视图(indexed views)(如果你运行的是企业版(Enterprise Edition))。

第2时期的完成是找到计划的成本对优化需要的时间之间的平衡。在这个时期生成的计划有完全级别(level of "Full")的优化。

它的花费需要多少?

这里提及的花费不能用多少秒或其他有意义的表达来衡量;它只是标记代表计划资源消耗值的一个任意数。然而,在早期的微软SQL Server世界里,它的起源是在桌面电脑上的基准检查程序(benchmark)(跑分)。

在计划里,每个运算符都有一个底线成本,然后用它来乘以行的大小和预计行数来获得那个运算符的成本,计划成本就是这些所有运算符的成本。

因为成本来自于底线值且与你的硬件速度无关,在每个SQL Server装置(同比版本 like-for-like version。博主注:与版本无关。)里生成每个计划的成本是一样的。

因为我们的SELECT查询非常简单,它退出在预优化时期的操作,因为这个计划对优化器非常明显(一个普通计划)。现在已经有查询计划了,它向查询执行器(Query Executor)去执行。

查询执行器(Query Executor)

查询执行器的工作是不释自明的,它执行查询。更准确的说,它通过干完包含与存储引擎相互作用的检索或修改数据的每一步来执行查询。

(此处有信息需要完善…………)

这个SELECT查询需要检索数据,因此请求传给存储引擎(Storage Engine)通过OLE DB接口传给存取方法(Access Methods)。

上图展示了作为优化器的输出的执行计划(query plan)正传给查询执行器(Query Executor),同时引入了存储引擎(Storage Engine),它被查询执行器(Query Executor)通过OLE作为接口给存取方法(Access Methods)。

存取方法(Access Methods)

存取方法是为你数据和索引提供存储结构,还有通过数据检索或数据修改接口的一批代码。它包含检索数据的所有代码单本身不执行操作,它向缓存区管理器(Buffer Manager)传递请求。

假设我们的SELECT语句需要读取一些记录行的数据刚好在一页。存取方法(Access Methods)的代码会让缓存区管理器(Buffer Manager)检索页,因此它可以准备一个OLE DB的记录集传回给关系引擎(Relational Engine)。

缓存区管理器(Buffer Manager)

缓存区管理器(Buffer Manager),如名所示,管理缓冲池(buffer pool),它代表着SQL Server的主要内存使用。如果你需要从页读一些记录行(当我们谈论UPDATE查询时会提及修改数据),缓存区管理器(Buffer Manager)在缓冲池(buffer pool)检查数据缓存看看在内存里是否有被缓存的这页。如果这页已被缓存了,结果就会传回给存取方法(Access Methods)。

如果这页没被缓存,然后缓存区管理器(Buffer Manager)从磁盘里拿这页,把它放入数据缓存(Data Cache),然后把结果传回给存取方法(Access Methods)。

你这里要记住的要点是你永远只和内存中的数据打交道。在作为记录集返回前,你请求的每个新的数据读取首先从磁盘读取,然后写回内存(数据缓存(the data cache))。

这就是为什么SQL Server需要在内存里保持最小级别的可用页面;如果第一时间在缓存里没有空间来放数据,你就不能读取任何新数据。

存取方法(Access Methods)代码决定SELECT查询需要一个新页,因此它向缓存区管理器(Buffer Manager)拿。缓存区管理器(Buffer Manager)检查它是否已在数据缓存(data cache),如果没找到的话就从磁盘加载到缓存。

数据缓存(Data Cache)

数据缓存一直是缓冲池(buffer pool)最大一部分;因此也是在SQL Server最大内存用户。这里每个从磁盘读取的数据页在被用之前都会被写回。

这个sys.dm_os_buffer_descriptors动态管理视图(DMV)每一行代表当前内存持有的每个数据页,你可以用这个脚本看看在数据缓存区(Data Cache)每个数据库占用多少空间:

 

复制代码
1 SELECT count(*)*8/1024 AS 'Cached Size (MB)'
2    ,CASE database_id
3         WHEN 32767 THEN 'ResourceDb'
4         ELSE db_name(database_id)
5         END AS 'Database'
6 FROM sys.dm_os_buffer_descriptors
7 GROUP BY db_name(database_id),database_id
8 ORDER BY 'Cached Size (MB)' DESC
复制代码

 

输出结果看起来会类似如下:

 

Cached Size (MB)  Database

 

3287              People

 

34                tempdb

 

12                ResourceDb

 

4                 msdb

这个例子里,People数据库在数据缓存(Data Cache)里有3287 MB数据页。

页在缓存里停留时间量由最近最少使用(least recently used:LRU)策略决定。

(此处有信息待完善………………) 

一个简单SELECT语句(查询)生命周期总结

SELECT查询的整个生命周期在这里被介绍:

  1. 在客户端的SQL Server网络接口(SNI)与在SQL Server使用例如TCP/IP的网络协议的网络接口(SNI)建立连接。然后在TCP/IP连接上建立与TDS终结点的联系并发送SELECT语句作为TDS消息发送给SQL Server。
  2. 在SQL Server上的SNI把TDS消息拆包,读取SELECT语句,传送一个“SQL命令”给命令分析器。
  3. 命令分析器在缓冲池检查计划缓存是否存在,与语句匹配的可用查询计划被命令分析器接收。如果没有找到它,基于SELECT语句创建查询树传给优化器来生成查询计划。
  4. 优化器在预编译生成零成本计划或普通计划,因为这个语句太简单了。生成的查询计划然后传给查询执行器去执行。
  5. 在执行时,查询执行器决定读取需要的数据来完整这个查询计划,因此通过OLE DB接口把请求传给在存储引擎里的存取方法。
  6. 存取方法需要从数据库里读一个页来完成来自查询执行器的请求,它让缓存区管理器来提供这个页。
  7. 缓存区管理器检查数据缓存看看它在缓存里是否已有。它不在缓存,因此从磁盘里拿这个页,放入缓存,传回给存取方法。
  8. 最后,存取方法把结果集送回给关系引擎发回给客户端。

本文转自Woodytu博客园博客,原文链接:http://www.cnblogs.com/woodytu/p/4472315.html,如需转载请自行联系原作者
相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情: https://www.aliyun.com/product/rds/sqlserver
相关文章
|
2月前
|
SQL 存储 数据挖掘
SQL Server 日期格式查询详解
SQL Server 日期格式查询详解
165 2
|
2月前
|
SQL 数据库
执行 Transact-SQL 语句或批处理时发生了异常。 (Microsoft.SqlServer.ConnectionInfo)之解决方案
执行 Transact-SQL 语句或批处理时发生了异常。 (Microsoft.SqlServer.ConnectionInfo)之解决方案
271 0
|
4月前
|
Java 应用服务中间件 Maven
从零到英雄:一步步构建你的首个 JSF 应用程序,揭开 JavaServer Faces 的神秘面纱
【8月更文挑战第31天】JavaServer Faces (JSF) 是一种强大的 Java EE 标准,用于构建企业级 Web 应用。它提供了丰富的组件库和声明式页面描述语言 Facelets,便于开发者快速开发功能完善且易于维护的 Web 应用。本文将指导你从零开始构建一个简单的 JSF 应用,包括环境搭建、依赖配置、Managed Bean 编写及 Facelets 页面设计。
100 0
|
4月前
|
SQL 存储 安全
Play Framework的安全面纱:揭开隐藏在优雅代码下的威胁
【8月更文挑战第31天】Play Framework 是一款高效、轻量级的 Web 开发框架,内置多种安全特性,助力开发者构建安全稳定的应用。本文详细介绍 Play 如何防范 SQL 注入、XSS 攻击、CSRF 攻击,并提供安全的密码存储方法及权限管理策略,通过具体示例代码展示实施步骤,助您有效抵御常见威胁。
66 0
|
4月前
|
SQL 存储 开发框架
Entity Framework Core 与 SQL Server 携手,高级查询技巧大揭秘!让你的数据操作更高效!
【8月更文挑战第31天】Entity Framework Core (EF Core) 是一个强大的对象关系映射(ORM)框架,尤其与 SQL Server 数据库结合使用时,提供了多种高级查询技巧,显著提升数据操作效率。它支持 LINQ 查询,使代码简洁易读;延迟加载与预先加载机制优化了相关实体的加载策略;通过 `FromSqlRaw` 或 `FromSqlInterpolated` 方法支持原始 SQL 查询;可调用存储过程执行复杂任务;利用 `Skip` 和 `Take` 实现分页查询,便于处理大量数据。这些特性共同提升了开发者的生产力和应用程序的性能。
189 0
|
4月前
|
SQL 关系型数据库 MySQL
【超全整理】SQL日期与时间函数大汇总会:MySQL与SQL Server双轨对比教学,助你轻松搞定时间数据处理难题!
【8月更文挑战第31天】本文介绍了在不同SQL数据库系统(如MySQL、SQL Server、Oracle)中常用的日期与时间函数,包括DATE、NOW()、EXTRACT()、DATE_ADD()、TIMESTAMPDIFF()及日期格式化等,并提供了具体示例。通过对比这些函数在各系统中的使用方法,帮助开发者更高效地处理日期时间数据,满足多种应用场景需求。
434 0
|
4月前
|
SQL 关系型数据库 MySQL
SQL Server、MySQL、PostgreSQL:主流数据库SQL语法异同比较——深入探讨数据类型、分页查询、表创建与数据插入、函数和索引等关键语法差异,为跨数据库开发提供实用指导
【8月更文挑战第31天】SQL Server、MySQL和PostgreSQL是当今最流行的关系型数据库管理系统,均使用SQL作为查询语言,但在语法和功能实现上存在差异。本文将比较它们在数据类型、分页查询、创建和插入数据以及函数和索引等方面的异同,帮助开发者更好地理解和使用这些数据库。尽管它们共用SQL语言,但每个系统都有独特的语法规则,了解这些差异有助于提升开发效率和项目成功率。
411 0
|
存储 SQL 程序员
【Sql Server】存储过程通过作业定时执行按天统计记录
通过前两篇文章的学习,我们已经对创建表、存储过程、作业等功能点有所了解 本次将结合前面所学习的知识点,创建统计表以及结合作业定时按天以及实时统计域名各个长度的记录值
402 0
【Sql Server】存储过程通过作业定时执行按天统计记录
|
存储 SQL 数据库
SQL Server——为什么要使用存储过程?不使用是什么样的?
提高数据库执行速度,可能第一次见到这句话的小伙伴们感觉到非常的匪夷所思叭!怎么就提高了它的执行速度捏,从哪方面可以表现出来呢?既然这里要说到的是为什么要使用存储过程,也就是说它的优点是什么。那我们肯定就要对使用和不使用存储过程两方面来进行对比才能看出它的优点对吧。
|
存储 SQL Go
SQL Server 存储过程
SQL Server 存储过程
159 0