Questions tagged «optimization»

在数据库的上下文中,优化是指查询优化器选择有效的物理执行计划的过程。


1
什么规则确定何时SQL Server使用CTE作为“优化围栏”?
不久前,Brent Ozar发表了一篇文章,详细介绍了SQL Server和PostgreSQL之间的一些区别: SQL Server与PostgreSQL之间的两个重要区别 第一点(“ CTE是优化栅栏”)引起了我的注意,因为很明显,在所提供的示例中,SQL Server将CTE和主查询组合在一起,并将其优化为单个查询(与之相反的行为是, PostgreSQL)。 但是,此行为似乎与我在其他博客和培训课程中看到的示例相反,在这些示例中,SQL Server确实将CTE视为优化围栏,从而可以更好地使用索引,提高性能等。例如: 选择星号的更好方法 因此,似乎SQL Server有时会“荣誉” CTE作为优化的围栏。是否有可用的良好资源来记录已知情况的特定列表,在这些情况下,SQL Server将可靠地认可CTE作为优化范围(或相反的行为)?

2
为什么这样更快并且使用安全吗?(第一个字母在字母表中)
长话短说,我们正在用很小的人表中的值更新小的人表。在最近的测试中,此更新大约需要5分钟才能运行。 我们偶然发现了似乎最简单的优化方法,该方法似乎完美无缺!现在,同一查询可以在不到2分钟的时间内运行,并且可以完美地产生相同的结果。 这是查询。最后一行添加为“优化”。为什么查询时间急剧减少?我们错过了什么吗?这会在将来引发问题吗? UPDATE smallTbl SET smallTbl.importantValue = largeTbl.importantValue FROM smallTableOfPeople smallTbl JOIN largeTableOfPeople largeTbl ON largeTbl.birth_date = smallTbl.birthDate AND DIFFERENCE(TRIM(smallTbl.last_name),TRIM(largeTbl.last_name)) = 4 AND DIFFERENCE(TRIM(smallTbl.first_name),TRIM(largeTbl.first_name)) = 4 WHERE smallTbl.importantValue IS NULL -- The following line is "the optimization" AND LEFT(TRIM(largeTbl.last_name), 1) IN ('a','à','á','b','c','d','e','è','é','f','g','h','i','j','k','l','m','n','o','ô','ö','p','q','r','s','t','u','ü','v','w','x','y','z','æ','ä','ø','å') 技术说明:我们知道要测试的字母列表可能还需要几个字母。我们还意识到使用“ DIFFERENCE”时明显的错误余量。 查询计划(常规): https : //www.brentozar.com/pastetheplan/? id …

2
根据更改日志计算库存数量
假设您具有以下表结构: LogId | ProductId | FromPositionId | ToPositionId | Date | Quantity ----------------------------------------------------------------------------------- 1 | 123 | 0 | 10002 | 2018-01-01 08:10:22 | 5 2 | 123 | 0 | 10003 | 2018-01-03 15:15:10 | 9 3 | 123 | 10002 | 10004 | 2018-01-07 21:08:56 | 3 4 …

1
从具有聚集索引的SQL Server表删除数据期间,B树是否重新平衡?
我在SQL Server数据库中有一个表,在主键上有聚簇索引。该表有100万行。如果我从表中删除了1万行,执行删除操作期间索引是否会被重组? 删除操作是存储过程的一部分。一次,一个以上的客户端可以执行该存储过程,但是每个单独的运行都将删除其自己的一组行(由主键唯一标识)。当多个客户端执行该过程时,我将无法使用(U型)键锁。阻止程序锁属于同一表中的一行,并且不属于任何同时运行的事务。不应有任何阻塞,因为每次运行都试图删除自己的行集。由于已关闭锁升级,因此不会发生。 我怀疑,删除操作一定会导致索引重新平衡,因此在重组过程中,它可能会对表的任何行进行键锁定。 我对此表示感谢。

2
如何确定添加索引的成本/收益?
根据Craig Ringer的说法: 虽然在引用侧外键列上(或包括)创建索引通常是一个好主意,但这不是必需的。每个索引添加减慢DML操作略有下降,所以你在每交纳履约成本INSERT,UPDATE或DELETE。如果很少使用该索引,则可能不值得使用。 您如何确定添加索引的好处是否超过其成本? 您是否在添加索引之前/之后分析了单元测试,并检查整体性能提升?或者,还有更好的方法?

1
如何“提示”递归CTE的基数?
我使用以下递归CTE作为最小示例,但总的来说,优化程序必须对递归CTE使用默认的“猜测”基数: with recursive w(n) as ( select 1 union all select n+1 from w where n<5 ) select * from w; /* n --- 1 2 3 4 5 */ explain analyze with recursive w(n) as ( select 1 union all select n+1 from w where n<5 ) select * …

1
表达式中的类型转换可能会影响查询计划选择中的“ CardinalityEstimate”吗?
我维护一个存档数据库,该数据库将历史数据存储在分区视图中。分区列是日期时间。该视图下的每个表都存储一个月的数据。 我们使用datetime列上的检查约束来约束每个表上的事件。这使优化器可以限制在搜索表中查找在事件datetime列上进行过滤的查询。 检查约束的名称由SQL Server生成,因此很难通过查看其名称来知道它们的作用。 我希望约束名称的格式为“ CK_TableName_Partition”。 我可以使用此查询并从sql_text列复制数据来生成重命名脚本。WHERE子句匹配检查约束,其名称看起来像是由SQL Server生成的: SELECT checks.name AS check_name, tabs.name AS table_name, skemas.name AS schema_name, cols.name AS column_name, N' EXECUTE sys.sp_rename @objname = N''' + skemas.name + N'.' + checks.name + N''', @newname = N''CK_' + tabs.name + N'_Partition'', @objtype = ''OBJECT'';' AS sql_text FROM sys.check_constraints AS …

3
通常如何存储数据库中行的每次更改的记录?
在我正在从事的项目中,必须跟踪对数据库某些表中行的每次更改,以进行进一步的审核或回滚。必须很容易找到谁修改了该行,从哪个IP地址以及何时修改了该行,并且能够还原以前的版本。 例如,Stack Exchange使用了类似的方法。当我更改其他人的问题时,可能会发现我已更改了该问题,并回滚了所做的更改。 假设我当前的架构具有与普通业务应用程序大致相同的属性(下),那么用于将每个更改存储到数据库中的对象的通用技术是什么? 对象的大小相对较小:nvarchar(1000)例如,可能会有一些,但不是很大的二进制数据斑点,该斑点直接存储在磁盘上,并且可以直接访问,而不是通过Microsoft SQL访问filestream, 数据库负载非常低,整个数据库由服务器上的一个虚拟机处理, 对先前版本的访问不必与对最新版本的访问一样快,但仍必须是最新版本¹,而又不能太慢²。 <tl-dr> 我考虑过以下情况,但是我对这种情况没有真正的经验,所以我会听到其他人的意见: 将所有内容存储在同一张表中,按ID和版本区分行。国际海事组织,这是非常愚蠢的,并且迟早会影响性能。使用这种方法,也不可能为最新项目和版本跟踪设置不同的安全级别。最后,每个查询的编写都会更加复杂。实际上,要访问最新数据,我将被迫按ID将所有内容分组并在每个组中检索最新版本。 将最新版本存储在一个表中,并在每次更改时将过时的版本复制到另一个架构中的另一个表中。缺陷在于,即使价值不变,我们每次也会存储每个价值。将不变的值设置null为并不是解决方案,因为我还必须跟踪何时将值更改为null或更改为null。 将最新版本存储在一个表中,将已更改属性及其先前值的列表存储在另一表中。这似乎有两个缺陷:最重要的是,在同一列中对异构类型的先前值进行排序的唯一方法是使用binary(max)。第二个是,我认为,在向用户显示以前的版本时,使用这种结构会更加困难。 执行与前两点相同的操作,但是将版本存储在单独的数据库中。从性能角度来看,为了避免通过在同一数据库中保留以前的版本来减慢对最新版本的访问,可能会很有趣。仍然,我认为这是一个过早的优化,只有在有证据证明在同一数据库中拥有较旧和最新版本是瓶颈时,才必须进行此优化。 </ tl-dr> ¹例如,将更改存储到日志文件中(就像处理HTTP日志一样),并在服务器负载最低的晚上将数据从日志刷新到数据库中是不可接受的。有关不同版本的信息必须立即可用或几乎立即可用;几秒钟的延迟是可以接受的。 ²信息访问频率不是很高,只有特定的用户组才能访问,但是仍然不能强迫他们等待30秒才能显示版本列表。同样,延迟几秒钟是可以接受的。

2
PostgreSQL是否优化添加具有非NULL默认值的列?
在添加NOT NULL带有DEFAULT值的列时-PostgreSQL是否优化了此操作? 如果表有n行,那么未优化的alter-table-add-column将产生默认值的n次写入-显然,这很痛苦。通过优化,数据库将立即创建新列,仅存储默认值的一个副本,当在合适的索引数据结构中找不到该列的非默认值时将返回该默认值。 例如,Oracle 11g进行了这样的优化。

3
自联接主键
考虑以下由N自我联接组成的查询: select t1.* from [Table] as t1 join [Table] as t2 on t1.Id = t2.Id -- ... join [Table] as tN on t1.Id = tN.Id 它生成具有N个聚集索引扫描和N-1个合并联接的执行计划。 老实说,我看不出没有理由不优化所有联接而仅执行一个聚集索引扫描,即为此优化原始查询: select t1.* from [Table] as t1 问题 为什么没有优化联接? 说每个联接都不会改变结果集在数学上是不正确的吗? 经过测试: 源服务器版本:SQL Server 2014(12.0.4213) 源数据库引擎版本:Microsoft SQL Server标准版 源数据库引擎类型:独立SQL Server 兼容性级别:SQL Server 2008(100) 查询没有意义;它只是浮现在我的脑海,我对此感到很好奇。 这是创建表和3个查询的小提琴:带有inner …

1
持久的计算列导致扫描
将常规列转换为持久计算列会导致此查询无法执行索引查找。为什么? 在多个SQL Server版本上进行了测试,包括2016 SP1 CU1。 复制 使用计算列 带有常规列 麻烦的是table1,col7。 表格和查询是原始文档的部分(简化)版本。我知道查询可以用不同的方式重写,并且出于某种原因可以避免该问题,但是我们需要避免触摸代码,而为什么table1找不到原因仍然存在。 正如保罗·怀特(Paul White)所展示的(谢谢!),寻道在强制的情况下仍然可用,所以问题是:为什么寻道未由优化程序选择,以及我们是否可以做一些不同的事情来使寻道按原样进行而不改变?码? 为了澄清有问题的部分,以下是不良执行计划中的相关扫描:

3
执行计划未使用INDEX,而是使用表扫描
我知道使用索引或表扫描时,SQL Server使用统计信息来查看哪个更好。 我有一个2000万行的表。我在(SnapshotKey,Measure)上有一个索引,并且此查询: select Measure, SnapshotKey, MeasureBand from t1 where Measure = 'FinanceFICOScore' group by Measure, SnapshotKey, MeasureBand 查询返回500k行。因此,查询仅选择表的2.5%的行。 问题是为什么SQL Server不使用我拥有的非聚集索引,而是使用表扫描? 统计信息已更新。 值得一提的是查询性能还是不错的。 表扫描 强制索引 表/索引结构 CREATE TABLE [t1]( [SnapshotKey] [int] NOT NULL, [SnapshotDt] [date] NOT NULL, [Measure] [nvarchar](30) NOT NULL, [MeasureBand] [nvarchar](30) NOT NULL, -- and many more fields …

5
进行扫描,尽管我希望进行搜索
我需要优化一条SELECT语句,但是SQL Server总是执行索引扫描而不是查找。这是查询,它当然在存储过程中: CREATE PROCEDURE dbo.something @Status INT = NULL, @IsUserGotAnActiveDirectoryUser BIT = NULL AS SELECT [IdNumber], [Code], [Status], [Sex], [FirstName], [LastName], [Profession], [BirthDate], [HireDate], [ActiveDirectoryUser] FROM Employee WHERE (@Status IS NULL OR [Status] = @Status) AND ( @IsUserGotAnActiveDirectoryUser IS NULL OR ( @IsUserGotAnActiveDirectoryUser IS NOT NULL AND ( @IsUserGotAnActiveDirectoryUser = …


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.