
SSMS可以提供可以查看正在执行的计划。live query plan可以查看一个查询的执行过程,从一个查询计划操作到另外一个查询计划操作。live query plan提供了整体的查询运行进度和操作级别的执行统计信息,比如产生的行数,执行的时间,操作进度等等。因为这些数据是实时的,不需要等待查询完成,这些统计信息对调试查询性能问题很有用。这个特性从SQL Server 2016开始,但是在2014上也可以运行了。 Remark 到SQL Server 2016,有2个方法开启Statistics infrastructure用来在其他回话查看live query statistics: 在目标会话上,执行 SET STATISTICS XML ON; 或者 SET STATISTICS PROFILE ON; 启动query_poist_execution_showplan扩展事件。这个是server级别的设置来启动live query Statistics。可以查看 从SQL Server 2016 SP1开始,SQL Server包含了一个轻量的Statistics infrastructure。这里有2个方法来启动轻量的Statistics infrastructure可以用来,在其他会话查看live query Statistics: 使用全局的trace flag 7412 或者启动query_poist_execution_showplan扩展事件
什么是系统版本的Temporal Table 系统版本的Temporal Table是可以保存历史修改数据并且可以简单的指定时间分析的用户表。 这个Temporal Table就是系统版本的Temporal Table因为每行的有效期由系统托管的。 每个Temporal Table有2个显示定义的列,类型是datetime2。这些用来表示有效期。这个列用来标记这个行是不是在期间内可用。 除了上面的period列,l临时表也包含了引用到其他表,系统使用这个表来保存行修改删除前的行版本。这个附加表可以认为是history表,主表包含了当前的行版本为当前表。在Temporal Table创建的时候可以指定一个history表或者让系统创建一个默认的history表。 临时表的工作原理 系统版本的表是有一对表,当前表和历史表。这些表都包含2个额外的datetime2字段用来定义每个行的可用期限: 期限开始列:系统把行的开始时间记录在这个列上,称为SysStartTime 期限结束列:系统把行的结束时间记录在这个列上,称为SysEndTime 当前表包含了每个行的当前值。历史表包含每个行的之前的只,starttime,endtime表示行的可用期限。 以下是一个例子: CREATE TABLE dbo.Employee ( [EmployeeID] int NOT NULL PRIMARY KEY CLUSTERED , [Name] nvarchar(100) NOT NULL , [Position] varchar(100) NOT NULL , [Department] varchar(100) NOT NULL , [Address] nvarchar(1024) NOT NULL , [AnnualSalary] decimal (10,2) NOT NULL , [ValidFrom] datetime2 (2) GENERATED ALWAYS AS ROW START , [ValidTo] datetime2 (2) GENERATED ALWAYS AS ROW END , PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo) ) WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.EmployeeHistory)); 可以删除括号中的HISTORY_TABLE系统会自动创建history表。 INSERT:对于一个insert,系统会设置SysStartTime列为当前事务的开始时间,SysEndTime为最大的值9999-12-31 UPDATE:对于update,系统会报之前的行保存到历史表并且设置SysEndTime为当前事务的启动时间。行被关闭,这个期限就是这个行的可用期限。这个行在当前表上的值被修改,那么SysStartTime被设置为当前事务的开始时间。SysEndTime被设置为最大时间。 DELETE:对于删除,系统把之前的行保存到history表,并且设置SysEndtime为事务的开始时间。标记行关闭,期限记录表示行的可用期限。当前表中行被删除。当前的查询不会被查到当前行。只有带时间的查询,或者直接查询历史表才能查到这个行。 MERGE:对于MERGE涉及到3个操作INSERT,UPDATE,DELETE,根据操作的不同做不同的记录。 临时数据查询 可以使用select from的for system_time子句来查询当前表和历史表的数据。 以下是查询的例子: SELECT * FROM Employee FOR SYSTEM_TIME BETWEEN '2014-01-01 00:00:00.0000000' AND '2015-01-01 00:00:00.0000000' WHERE EmployeeID = 1000 ORDER BY ValidFrom; 注意: FOR SYSTEM_TIME会过滤掉SysStartTime=SysEndTime的数据。这些行在同一个事务里面操作了同一行儿产生。只能通过查询历史表才能返回 关于SYSTEM_TIME过滤 表达式 符合条件的行 Description AS OF<date_time> SysStartTime <= date_time AND SysEndTime > date_time 返回一个表,其行中包含过去指定时间点的实际(当前)值。 在内部,临时表及其历史记录表之间将进行联合,然后筛选结果以返回在 <date_time> 参数指定的时间点有效的行中的值。 如果 system_start_time_column_name 值小于或等于 <date_time> 参数值,并且 system_end_time_column_name 值大于 <date_time> 参数值,则此行的值视为有效。 FROM<start_date_time>TO<end_date_time> SysStartTime < end_date_time AND SysEndTime > start_date_time 返回一个表,其中包含在指定的时间范围内保持活动状态的所有行版本的值,不管这些版本是在 FROM 自变量的 <start_date_time> 参数之前开始活动,还是在 TO 自变量的 <end_date_time> 参数值之后停止活动。 在内部,将在临时表及其历史记录表之间进行联合,然后筛选结果,以返回在指定时间范围内任意时间保持活动状态的所有行版本的值。 正好在 FROM 终结点定义的下限时间停止活动的行将被排除,正好在 TO 终结点定义的上限时间开始活动的记录也将被排除。 BETWEEN<start_date_time>AND<end_date_time> SysStartTime <= end_date_time AND SysEndTime > start_date_time 与上面的 FOR SYSTEM_TIME FROM <start_date_time>TO<end_date_time> 描述相同,不过,返回的行表包括在 <end_date_time> 终结点定义的上限时间激活的行。 CONTAINED IN (<start_date_time> , <end_date_time>) SysStartTime >= start_date_time AND SysEndTime <= end_date_time 返回一个表,其中包含在 CONTAINED IN 参数的两个日期时间值定义的时间范围内打开和关闭的所有行版本的值。 正好在下限时间激活的记录,或者在上限时间停止活动的行将包括在内。 ALL 所有行 返回属于当前表和历史记录表的行的联合。 注意: 可以通过Hidden隐藏期限列,删除表需要先关闭系统版本 ALTER TABLE Employee SET (SYSTEM_VERSIONING =off )之后才能删除表
使用Query Store监控性能 SQL Server Query Store特性可以让你看到查询计划选择和性能。简化了性能调优,可以快速的发现因为查询计划的选择导致的性能的差别。Query Store自动历史的查询,计划和运行时的统计信息,保留这些可以用来检查。数据通过时间窗口来分隔数据,你可以看见数据库的使用模式,并且理解查询计划在服务中的变化。可以你使用ALTER DATABASE SET选项来配置Query Store。 启动Query Store ALTER DATABASE AdventureWorks2012 SET QUERY_STORE = ON; Query Store中的信息 特定查询的执行计划涉及到很多,比如统计信息变化,schema变化,索引的创建和删除等等。过程的执行计划只会保存最新的执行计划,计划也会因为内存压力来牺牲计划的cache。因为执行计划的变化导致性能问题也是比较多的。 因为每个查询都保留了多个执行计划,可以通过策略强制查询处理器使用特定的执行计划。Query Store的计划强制和查询hint的USE PLAN相似,不需要应用程序做任何修改。计划强制可以解决查询的计划修改导致的性能退化。 Wait Stats,是另外一个source用来调优SQL Server。对于长时间,wait stats是实例级别的,并不能回归到实际查询。在SQL Server 2017,在Query Store中增加另外一个维度来跟踪wait stats。 Query Store特性使用场景: 快速查找和通过强制到之前的查询计划,修复一个计划性能回归 时间窗口内查询的运行次数。 查看过去的x小时,top n查询 审计给定查询的查询计划 分析特定数据库的资源使用 等待resource的top n查询 理解特定查询和计划的wait nature Query Store包含的三个Store: plan store,用来保存执行计划信息 runtime stats store,保存执行的统计信息 wait stats store,保存wait stats 可以通过max_plans_per_query配置每个查询的保存的plan数量,为了提高性能写入这些store都是一部的,为了最小化空间的使用运行时的统计信息,按某个时间范围内聚合。 以下查询返回query store中的查询和计划: SELECT Txt.query_text_id, Txt.query_sql_text, Pl.plan_id, Qry.* FROM sys.query_store_plan AS Pl JOIN sys.query_store_query AS Qry ON Pl.query_id = Qry.query_id JOIN sys.query_store_query_text AS Txt ON Qry.query_text_id = Txt.query_text_id ; 查找等待查询 从SQL Server 2017开始每个查询的等待信息,可以使用 sys.query_store_wait_stats (Transact-SQL) 查询
存储格式修改 在2014,2016中修改了内存优化表的存储格式,新的格式是序列的并且the database is restarted once during database recovery. ALTER TABLE日志优化,并且可以并发运行 当你在内存优化表执行ALTER TABLE,只有元数据的修改会被写入日志。这样减少了大量的日志。并且很多ALTER TABLE是并行的,这样可以减少语句运行的时间 但是如果包含LOB,就不能并行运行 统计信息 优化表的统计信息可以自动更新。另外可以通过采样来收集统计信息,不需要进行表扫描 内存优化表的并发和heap扫描 内存优化表和索引,只是并行扫描。对于分析的查询可以提高性能。 另外,heap扫描也进行并发扫描。 内存优化表的TSQL增强 在SQL Server 2014很多TSQL语句都不能使用,现在在2016上可以使用了: 支持唯一约束和索引 支持内存优化表间的外键 外键只能引用主键,不能用唯一建 支持check约束 非唯一索引支持key中的null 支持内存优化表上的触发器 只支持AFTER的触发器,INSTADOF触发器不支持 内存优化表中的任何触发器必须使用WITH NATIVE_COMPILATION。 内存优化表,多列,行大小可以超过8060字节。 支持LOB类型 natively compiled的TSQL增强 略 性能和扩展性的提高 数据大小不在限制 支持多个线程把内存优化表的修改持久化到磁盘 InterOp支持多线程访问 SSMS的增强 略
新的 ALTER DATABASE SCOPED CONFIGURATION (Transact-SQL) 用来配置数据库级别配置。 这个语句可以配置每个数据库的配置: 清理过程cache 设置MAXDOP参数,可以配置primary和secondary 设置查询优化器的评估模式 启动和关闭数据库级别的参数嗅探 启动和关闭数据库级别的查询优化补丁 启动和关闭数据库级别的identity cache 语法: ALTER DATABASE SCOPED CONFIGURATION { { [ FOR SECONDARY] SET <set_options> } } | CLEAR PROCEDURE_CACHE | SET < set_options > [;] < set_options > ::= { MAXDOP = { <value> | PRIMARY} | LEGACY_CARDINALITY_ESTIMATION = { ON | OFF | PRIMARY} | PARAMETER_SNIFFING = { ON | OFF | PRIMARY} | QUERY_OPTIMIZER_HOTFIXES = { ON | OFF | PRIMARY} | IDENTITY_CACHE = { ON | OFF } } 参数: FOR SECONDARY 指定设置secondary的数据库 MAXDOP = { <value> | PRIMARY} 设置MAXDOP,默认为0,如果设置了再数据库执行的时候会覆盖sp_configure中的配置,如果有查询提示,查询提示会覆盖这个配置。 PRIMARY的意思是,如果在secondary上设置了primary,那么secondary会集成primary上的设置。 LEGACY_CARDINALITY_ESTIMATION = { ON | OFF | PRIMARY} 可以让你设置查询优化器评估模式,如果为OFF会根据兼容级别使用查询优化器评估模式,如果为ON使用老的查询优化器的评估模式。 PRIMARY和上面的一样 PARAMETER_SNIFFING = { ON | OFF | PRIMARY} 启动和关闭参数嗅探 QUERY_OPTIMIZER_HOTFIXES = { ON | OFF | PRIMARY} 启动和关闭查询优化补丁,和数据库兼容级别无关。默认是OFF,关闭查询优化补丁,关于补丁具体看 Microsoft Support article. CLEAR PROCEDURE_CACHE 清理过程计划可以在primary,secondary中执行。 IDENTITY_CACHE = { ON | OFF } 启动和关闭数据库级别的identity cache。默认是on,identity cache用来提高insert在identity中的性能。为了避免identity的间隙可以选择关闭。