我有一个这样的查询:
SELECT col1
FROM MyTable
WHERE
DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()))
BETWEEN col2
AND col3
;
Run Code Online (Sandbox Code Playgroud)
这给出了与此类似的执行计划的工具提示:

dateadd搜索谓词的一部分是否对查询中的每一行执行?或者 SQL Server 是否为整个查询计算一次值?
三张表:
product:与列: ( a, g, ...a_lot_more... )
a: PK, clustered
g: bit-column
Run Code Online (Sandbox Code Playgroud)
main:与列: ( c, f, a, b, ...a_lot_more... )
c: PK, clustered
f: bit-column
(a, b): UQ
Run Code Online (Sandbox Code Playgroud)
lookup 带列: ( a, b, c, i )
(a, b): PK, clustered
a: FK to product(a)
c: UQ, FK to main(c)
i: bit-column
Run Code Online (Sandbox Code Playgroud)
我找不到合适的连接索引:
FROM
product
JOIN
lookup
ON lookup.a = product.a
JOIN
main
ON main.c = lookup.c
WHERE
product.g = 1
AND
main.f = 1
AND
lookup.i = 1 …Run Code Online (Sandbox Code Playgroud) 
今天我在 The Heap 上,正在查看我认为可以改进的查询计划。然而,它创造了一些东西,动摇了我对 SQL Server 查询优化器的信念。如果sql-server甚至不能计数到 100%,我还可以信任它吗?
表的特点:
date_entered列有没有人以前见过这个,是什么导致计划看起来如此扭曲?

我注意到,当 tempdb 事件溢出(导致查询缓慢)时,对于特定连接,行估计通常会偏离。我已经看到溢出事件发生在合并和散列连接中,它们通常将运行时间增加 3 到 10 倍。这个问题涉及如何在减少溢出事件机会的假设下改进行估计。
实际行数 40k。
对于此查询,计划显示错误的行估计(11.3 行):
select Value
from Oav.ValueArray
where ObjectId = (select convert(bigint, Value) NodeId
from Oav.ValueArray
where PropertyId = 3331
and ObjectId = 3540233
and Sequence = 2)
and PropertyId = 2840
option (recompile);
Run Code Online (Sandbox Code Playgroud)
对于此查询,计划显示了良好的行估计(56k 行):
declare @a bigint = (select convert(bigint, Value) NodeId
from Oav.ValueArray
where PropertyId = 3331
and ObjectId = 3540233
and Sequence = 2);
select Value
from Oav.ValueArray
where ObjectId = @a
and PropertyId = 2840
option (recompile); …Run Code Online (Sandbox Code Playgroud) 根据克雷格·林格的说法:
虽然在(或包括)引用端外键列上创建索引通常是个好主意,但这不是必需的。您添加的每个索引都会稍微减慢 DML 操作的速度,因此您需要为每个
INSERT,UPDATE或支付性能成本DELETE。如果索引很少使用,它可能不值得拥有。
您如何确定添加索引的收益是否超过其成本?
您是否在添加索引之前/之后分析单元测试并检查整体性能提升?或者,还有更好的方法?
我在 SQL Server 数据库中有一个表,主键上有一个聚集索引。该表有 100 万行。如果我从表中删除 10K 行,在执行删除操作期间索引会被重组吗?
删除操作是存储过程的一部分。一次,可以有多个客户端执行存储过程,但是每次运行都会删除它自己的一组行(由主键唯一标识)。当多个客户端执行该过程时,我会阻塞键锁(U 型)。阻塞锁属于同一个表中的一行,它不属于任何并发运行的事务。不应该有任何阻塞,因为每次运行都试图删除它自己的一组行。锁定升级不会发生,因为它已关闭。
我怀疑,删除操作一定会导致索引重新平衡,因此在重组过程中,它可以对表的任何行进行键锁定。
我真的很感激对此的任何意见。
我知道在使用索引或表扫描时,SQL Server 使用统计信息来查看哪个更好。
我有一个有 2000 万行的表。我在 (SnapshotKey, Measure) 和这个查询上有一个索引:
select Measure, SnapshotKey, MeasureBand
from t1
where Measure = 'FinanceFICOScore'
group by Measure, SnapshotKey, MeasureBand
Run Code Online (Sandbox Code Playgroud)
查询返回 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
) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)
表上没有PK,因为它是一个数据仓库。
CREATE NONCLUSTERED INDEX [nci_SnapshotKeyMeasure] ON [t1]
(
[SnapshotKey] ASC,
[Measure] ASC
)
Run Code Online (Sandbox Code Playgroud) index sql-server optimization execution-plan sql-server-2012
将常规列转换为持久计算列会导致此查询无法执行索引查找。为什么?
在多个 SQL Server 版本上进行了测试,包括 2016 SP1 CU1。
问题在于table1, col7。
表和查询是原始版本的部分(和简化)版本。我知道查询可以用不同的方式重写,并且出于某种原因避免了这个问题,但我们需要避免接触代码,为什么table1不能被搜索的问题仍然存在。
正如 Paul White 所展示的(谢谢!),如果强制执行,则搜索可用,所以问题是:为什么优化器不选择搜索,以及我们是否可以做一些不同的事情来使搜索按预期进行,而无需更改代码?
为了澄清有问题的部分,这是错误执行计划中的相关扫描:

假设您有以下表结构:
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 | 123 | 10004 | 0 | 2018-02-09 10:03:23 | 1
Run Code Online (Sandbox Code Playgroud)
FromPositionId并且ToPositionId是股票头寸。某些位置 ID:s 具有特殊含义,例如0。事件 from 或 to0表示库存已创建或删除。From0可能是交货的库存,to0可能是发货的订单。
该表目前包含大约 550 …
长话短说,我们正在使用非常大的人员表中的值更新小型人员表。在最近的测试中,此更新需要大约 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','æ','ä','ø','å')
Run Code Online (Sandbox Code Playgroud)
技术说明:我们知道要测试的字母列表可能需要更多的字母。我们也意识到使用“DIFFERENCE”时明显的误差幅度。
查询计划(常规): https : //www.brentozar.com/pastetheplan/?
id = rypV84y7V 查询计划(带“优化”):https : //www.brentozar.com/pastetheplan/?id=r1aC2my7E