内存中 OLTP

9/1/2015来源:SQL技巧人气:1519

内存中 OLTP - 常见的工作负荷模式和迁移注意事项(三)

----------------------------我是分割线-------------------------------

本文翻译自微软白皮书《In-Memory OLTP – Common Workload Patterns and Migration Considerations》:http://technet.microsoft.com/en-us/library/dn673538.aspx

译者水平有限,如有翻译不当之处,欢迎指正。

----------------------------我是分割线-------------------------------

将应用程序迁移到内存中OLTP

内存中OLTP集成到SQL Server中的同时,也具备不同于传统关系型数据库系统特别是SQL Server的一些独特功能。本节的目的是向读者提供一些这样的注意事项。本节并不提供有关迁移的综合指导,许多关于具体需求,支持功能和外围应用的深入讨论已超出了本文的范围。

为迁移评估工作负荷

如先前所讨论的,许多应用程序已经从实施内存中OLTP中受益颇丰。然而,不同的工作负荷可能会获得不同程度的改进。有些应用程序可能只需要极小的更改,而其他可能需要更大量的代码修改,例如将某些Transact-SQL转换成本地编译的存储过程。也有一些场景并不适合于内存中OLTP。因此,关键是要了解工作负荷和环境的特征。这项评估将帮助你确定一个应用程序对于内存中OLTP是否是一个可行的候选。以下章节将提出审核应用程序工作负荷的方法,并提供了有关这些内存中OLTP实施的可行性意见。

迁移方法论

在迁移到内存中OLTP之前,确保你彻底了解应用程序的需求和目标。此外,确定性能瓶颈是否可以由内存中OLTP解决。如下图表明, SQL Server引擎其中某些方面可以为内存中OLTP提供收益。其他与引擎交互的组件有可能不能从迁移到内存中OLTP获得收益。

图6 内存中OLTP的性能收益范围

如图6所示,内存中OLTP位于数据访问层(表和索引对象)和查询执行的引擎组件。如果当前的瓶颈位于这个领域,将这些数据集或者Transact-SQL迁移到内存中OLTP引擎中则可以提高性能。内存中OLTP比起基于磁盘的表产生的日志量也更少,因为不需要为索引分配或者UNDO需求写入日志记录。在任何情况下,到磁盘子系统I/O的日志延迟仍然是事务提交的一部分。比如SCHEMA_ONLY表(非持续)和延迟的持续性这样的功能能够消除或尽可能减少这方面的开销。另外,客户端连接层没有任何增强。有一些方式能够处理这个问题,但内存中OLTP并不能直接处理或解决这一瓶颈。

建立基线

确定基线是了解系统的当前性能和在做出更改后衡量改进或退化的关键。你可以以多种方式来实现这一点。许多工具和方法论在“监视和优化性能”这篇文章中都进行了讨论。很多工具可以用来帮助确定一个基线,但选择一个度量充当基线是非常重要的。基线度量的一些例子有:

  • 系统组件的利用率和性能,比如:磁盘,CPU,内存,网络。
  • SQL Server代码执行时间。
  • 事务吞吐量。
  • 什么系统正在等待,以及等待多长时间。比如sys.dm_os_wait_stats这样的动态管理视图可以帮助确定SQL Server的资源等待。

应用程序的整体性能也应该被视为基线的一部分。确定基线还要考虑以下因素:

  • 衡量业务事务吞吐量。
  • 事务往返时间。
  • 用户体验。
  • 扩展。

使用这些衡量可以帮助定义成功迁移的标准。

瓶颈分析

在某些情况下,数据库引擎之外的因素可能会导致应用程序中的瓶颈。因此,迁移到内存中OLTP可能不会改善这种状况。了解当前的性能瓶颈在整体应用架构是至关重要的。一旦你确定了数据库中的瓶颈,则为迁移重点关注这些特定的组件。

使用内存OLTP工具来分析工作负荷并帮助迁移

内存中OLTP产品提供了一些工具来帮助迁移过程。这些工具都集成到了Management Studio中。我们有时提到的工具集是指分析,迁移和报表(Analyze, Migrate, and Reporting , AMR)工具集。为了帮助瓶颈分析,可以使用新的数据收集器(事务性能收集组)。它们帮助收集性能数据和工作负荷特性。它们还能建议将频繁使用的或者有争用的表和代码迁移到内存中OLTP。

数据收集器比起运行单个查询来为内存中OLTP迁移确定一个很好的候选要更有意义得多。收集器使用管理数据仓库(MDW)对时间段内收集的数据执行数据聚合。收集器能够提供关于迁移到内存中OLTP带来的性能提升的预估。这个信息出现在SQL Server 2014 Management Studio中附带的“事务性能分析”报表中。有关配置和使用这些工具的详细讨论,请参阅网页“迁移到内存中OLTP”,其中有关于这一功能的详细介绍。

如果你不能利用数据收集和报告工具,还有其他方式来帮助理解SQL Server中的争用点。 SQLDiag,PSSDiag和SQL Nexus是你可以用来确定与闩锁,锁,自旋锁和存储过程的执行次数统计相关的争用问题的工具。 SQL Nexus能够确定等待资源,闩锁,锁和阻塞。如果SQL跟踪作为捕获的一部分运行,SQL Nexus还可以捕获执行次数最多的存储过程和Transact-SQL语句。

如果在一段时间内监视和收集这些信息的开销过大,你有另一个选择。你可以手动执行查询来检测经常访问的表,闩锁争用或者存储过程执行次数的统计。这些查询的执行提供了自从上次服务器重启以来位于内存中的快照值。在某些情况下,捕捉两个时间点的输出并确定它们之间的增量可能更加准确。收集这些信息的查询在稍后的章节中提供。

经常访问的表

这个查询提供了自从SQL Server实例被重置或者性能数据被清除以来数据库中访问最频繁的表的一个列表。在确定进行转换的候选时,可考虑靠前的检索数和扫描数。通过评估以下查询的singleton_lookup_count和range_scan_count,你可以对使用率有一些了解。对于迁移到内存中OLTP,可考虑将频繁访问的表或表中的部分数据迁移到内存优化对象中。

SELECT TOP (5)     b.name AS TableName,            a.database_id,            a.singleton_lookup_count,            a.range_scan_count    FROM     sys.dm_db_index_Operational_stats(DB_ID(), NULL, NULL, NULL) AS a        INNER JOIN sys.objects b on a.object_id = b.object_idWHERE     b.type <> 'S'        AND         (a.singleton_lookup_count > 0 OR a.range_scan_count > 0)ORDER BY     a.singleton_lookup_count DESCGO

闩锁争用

通过审核sys.dm_db_index_operational_stats动态管理视图中的page_latch_wait 和 page_lock_wait列来评估闩锁争用。考虑将具有大量闩锁或锁争用的表迁移到内存中OLTP。以下查询将提供自从SQL Server实例被重置或者性能数据被清除以来累计的闩锁和锁等待。

SELECT TOP (5)    a.database_id,            so.object_id,            so.name AS TableName,            a.page_latch_wait_count    ,            a.page_latch_wait_in_ms,            a.page_lock_wait_count,            a.page_lock_wait_in_msFROM    sys.dm_db_index_operational_stats(DB_ID(), NULL, NULL, NULL) a        INNER JOIN sys.objects AS so         ON a.object_id = so.object_idWHERE    so.type = 'U' AND a.page_io_latch_wait_count > 0ORDER BY     a.page_latch_wait_count DESC;

存储过程执行次数的统计

内存中OLTP提供本地编译的存储过程。通过本地编译Transact-SQL成一个DLL文件并尽可能减少在执行时需要被处理的指令,从而极大的改善存储过程的执行时间。如果你无法使用Management Studio中的工具,以下这两个查询将提供类似的信息。然而,这些查询只能检索到这个调用执行时存在于计划缓存中的存储过程和Transact-SQL数据。有可能有更好的候选存储过程存在,但它们已经不在计划缓存中。可考虑在一天或一周中多次运行这些查询,以确定是否存在其他的候选。

以下查询将提供总工作时间最多的存储过程名称。如果最近性能数据已经清零,计划缓存会失效,或者如果SQL Server实例已被重置,则此刻计划缓存可能不具有足够多有价值的信息。

SELECT TOP (10)    sp.database_id,            so.name AS StoredPRocName,            sp.total_worker_time,            sp.execution_count,            sp.total_logical_reads,            sp.total_logical_writes,            sp.total_logical_readsFROM    sys.dm_exec_procedure_stats AS sp        INNER JOIN sys.objects AS so         ON (sp.object_id = so.object_id)WHERE    so.type = 'P' AND sp.database_id = DB_ID()ORDER BY sp.total_worker_time DESC;

以下查询检索出的数据在Management Studio工具中并不可用。但是,它可能有助于确定存储过程中的哪个语句是资源最多的消耗者。在决定哪些存储过程迁移到内存中OLTP时,知道哪些语句最多消耗资源是有价值的。这可能对只将一些高资源消耗的语句而不是整个存储过程迁移到本地编译的存储过程中有益。

SELECT TOP (50)    sp.database_id,            dbname= DB_NAME (qt.dbid),            so.name AS StoredProcName,            sp.total_worker_time,            sp.execution_count AS StoredProcedureExecCount,            qs.execution_count AS StatementExecCount,            SUBSTRING(qt.text,qs.statement_start_offset / 2 + 1,                (CASE WHEN qs.statement_end_offset = -1                THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2 ELSE qs.statement_end_offset END - qs.statement_start_offset) / 2                 ) AS query_textFROM    sys.dm_exec_query_stats AS qs         CROSS APPLY         sys.dm_exec_sql_text(qs.sql_handle) AS qt         INNER JOIN sys.dm_exec_procedure_stats AS sp            ON (sp.sql_handle = qs.sql_handle)        INNER JOIN sys.objects so         ON (sp.object_id = so.object_id) and sp.database_id = DB_ID()ORDER BY sp.total_worker_time DESC, qs.execution_count DESC

大规模下使用有代表性的工作负荷指导测试

定义了目标和瓶颈之后,考虑一个测试标准来模拟瓶颈是很重要的。这个测试也将决定你是否能达到目的。可能有一些场景,其中的一个“单元测试”或工作负荷的特定部分的单次执行,将有助于确认目标。例如,值得关注的可能是在隔离下跨单个线程的存储过程调用的延迟。然而,在许多情况下,只有在负荷下,瓶颈或者性能降低才会暴露出来,尤其是对于大规模下的争用。

如果你只在大规模的场景下观察到瓶颈,在产生争用之前,使用与不使用内存中OLTP执行的测试可能会显示相似的性能。一旦达到引发争用的规模,从这时开始,你会观察到使用内存中OLTP有显著的改善。在许多情况下,在传统的数据库系统中,吞吐量将达到一个平衡或者执行时间将增加。这时,从性能的角度上看,系统上额外的负荷或者规模很可能会造成性能不再提高甚至产生负面的影响。内存中OLTP中这一瓶颈的缓解有助于极好的维持和提高应用程序的整体性能,并跨越这个观察到的瓶颈。

图7展示了转换到内存中OLTP的AdventureWorks示例数据库的利用。图像显示了随着一个工作负荷一直运行到大规模下出现争用时引擎的性能提升。你只能通过模拟达到一个典型的RDBMS中规模影响性能的点的测试来认识这些好处。图中的圆圈表示在这个点,典型RDBMS执行明显需要花费更多的时间来执行同样数量的事务数。在这一点后,内存中OLTP工作负荷继续几乎呈线性的扩展,而基于磁盘的工作负荷则达到大规模的一个障碍。

图7从AdventureWorks示例数据库中执行DemoInsertSalesOrders的完成时间/线程数

最后,需要考虑的是,当你将工作负荷迁移到内存中OLTP,工作负荷的一些特征有可能改变。理想的情况是基于一个稳定的,明确的工作测量来衡量整体应用程序的性能。图7显示了基于“N”的理想值,N表示用户的线程数(针对时间的测量)。比起其范围在每次执行时可能发生变化的某个值,比如业务事务或者并发用户数这样的测量更容易在不同的测试间关联起来。

有目标的,迭代的迁移方法

我们建议你通过先着重于工作负荷中的特定领域来开始迁移,这部分领域表现出的瓶颈应该是内存中OLTP可以解决的。通常情况下,你可能只需将数据和对象的一个子集迁移到内存中OLTP就能实现显著的收益。

关键表到内存优化结构和Transact-SQL代码到编译代码的一些迁移都非常简单,只需要极少的变更。其他情况由于外围应用支持或者部署这些新数据库对象的能力,可能需要复杂的变更。

集成到SQL Server 2014 Management Studio中的两个帮助迁移对象的工具是内存优化顾问和本地编译顾问。这两种工具可以帮助你评估迁移的难度。它们评估表架构和存储过程的语法来寻找可能的迁移阻碍,比如不支持的数据类型。然后这些工具可以提供解决这些迁移阻碍的方法的信息。如果内存优化顾问未检测到迁移的问题,它的向导可以帮助创建内存优化表和数据迁移。

由于内存中OLTP集成到SQL Server中,它可以让你一起使用内存优化表和基于磁盘的表。内存中OLTP还允许解释型Transact-SQL和本地编译的存储过程来访问存储在内存优化表中的数据。如果你最终一定要迁移特定的组件,请使用以下增量迁移的策略:

  • 确定限制可扩展性的争用和瓶颈表。
  • 解决不支持的功能,并将关键数据迁移到内存优化表。
  • 执行使用解释型Transact-SQL访问内存优化表所需的最少的代码变更。

这些步骤应该能够减缓与锁和闩锁相关的大部分可扩展性的问题。如果你需要额外的性能提升,特别是与Transact-SQL执行时间相关,那么需要实施将Transact-SQL迁移到本地编译的存储过程。

  • 确定访问这些表及其相关对象的对于性能至关重要的Transact-SQL。
  • 解决不支持的语言结构并将这些存储过程迁移为本地编译的代码。

图8 迁移方法论

当你将特定的瓶颈领域迁移到内存中OLTP,系统的其他部分可能会成为新的瓶颈。当解决一个特定的瓶颈时,考虑采用迭代的方法来迁移,然后分析解决方案的下一个性能瓶颈可能存在的位置。

实施中需要进一步注意的事项

本节不提供内存中OLTP技术的综合列表。本节提供采用这项新技术功能的一些关键注意事项的指导。我们强调了一些技术或决策点,与传统的SQL Server实施相比,这些技术或决策点是全新的或者巨大的变革。

硬件或系统影响的注意事项

性能敏感的工作负荷依赖部署中的所有组件,包括软件和硬件。在下面的章节中,我们讨论了考虑硬件选择的一些关键因素,以及在部署内存中OLTP时,实施的一些注意事项。基于允许应用程序使用现今市场上可用的已有和商用硬件的概念,微软开发了内存中OLTP。内存中OLTP并不需要特别多的插槽/内核或者其他硬件组件。内存中OLTP是以 SQL Server中可与标准的商用硬件交互的优化作为目标。

内存

内存优化表完全驻留在内存中,并且不会对于施加于SQL