Ser*_*ook 3 sql-server-2008-r2
我认为我可以提出问题的最佳方式是从一个例子开始。
想象一下这两个查询:
SELECT CAR.SerialNumber, TIRE.SerialNumber
FROM dbo.tCar AS CAR
INNER JOIN dbo.tTire AS TIRE ON ( TIRE.CarID = CAR.ID)
WHERE CAR.Brand = 'Jaguar'
Run Code Online (Sandbox Code Playgroud)
和
SELECT CAR.SerialNumber, TIRE.SerialNumber
FROM dbo.tCar AS CAR
CROSS APPLY (
SELECT TIRE.SerialNumber
FROM dbo.tTire AS TIRE
WHERE TIRE.CarID = CAR.ID
) AS TIRE
WHERE CAR.Brand = 'Jaguar'
Run Code Online (Sandbox Code Playgroud)
注意:tTire.CarID 被索引,tCar.Brand 被索引
这两个将返回相同的输出。
我知道第二个查询只是愚蠢的,但同样,它只是作为我问题的一个例子。
现在,我猜(即使我不知道详细信息)SQL Server 将对第一个查询(JOIN)读取的数据执行一个巧妙且有限的锁定。
但我想知道它将如何为第二个查询(APPLY)读取的数据执行锁定,主要(显然是 imo)在“tTire”数据读取上。
万一加锁APPLY
怎么办SQL Server perfom
?
编辑:这个例子很简单,似乎 SQL Server 设法创建了相同的执行计划,但我的“应用”问题应该是在 RBAR 效应发生的地方。
Pau*_*ite 10
查询不是可执行程序。SQL查询规范语言使我们能够定义查询的逻辑结果,但由查询优化器和执行引擎等组件负责处理传递这些结果所涉及的物理处理。
原则上,事物的物理处理端可以自由地执行它喜欢的任何操作,只要返回的数据与查询规范相匹配。它可以使用散列、扫描、排序……任何它喜欢的东西,只要结果与查询的逻辑相匹配。
例如,优化器可能会为您的两个示例查询生成非常相似(甚至相同)的用户可见执行计划,因为它们在逻辑上描述了相同的结果。另一方面,它可能不会;无论哪种方式都无关紧要。
这里的第二个主要因素涉及执行查询的事务隔离级别。可用的不同隔离级别各自提供了关于由于另一个查询的并发数据修改而对一个查询的影响的不同保证。
锁只是数据库引擎可以强制执行这些隔离保证的一种可能机制。其他完全不使用锁的隔离实现在 SQL Server 以及大多数主流产品中都是可用的。
关键是引擎保证遵守请求的隔离级别,它可能会使用锁来做到这一点,也可能不会。从实际的角度来看,这些细节有时可能很重要(例如发生阻塞时),但它们并不是真正的基础。
由于所有这些,查询的原始书面形式与可能采取的锁定之间通常没有直接关系 - 中间有太多其他“东西”在进行。
在处理 RBAR 场景时,SQL Server 的行为甚至没有已知的“趋势”吗?有什么需要注意的吗?
这与经验有关,尽管这并非普遍意义上的好事。当然有很多建议,尽管有些已经过时,或者基于误解。
在 SQL Server 中,我们通常可以安全地鼓励“基于集合的思维”,并说通常应该避免游标、循环和逐行处理,但这还不是全部,尽管这有点超出你原来的问题。
我通常的建议是首先针对精心设计和维护的数据库编写好的查询(使用您认为最自然的任何语法),然后担心任何特定问题,如锁定(优化器限制、计划形状问题等),如果它们出现的话。人们有时确实会因为错误的原因而学会避免诸如“申请”之类的事情,并且不得不在以后完全忘记它。
总的来说,我对总是偏爱一种语法元素或结构而不是另一种的建议持怀疑态度。
资源: