视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
SQLServer利用锁提示优化Row_number()-程序员需知_MySQL
2020-11-09 20:10:54 责编:小采
文档
 网站中一些老页面仍采用Row_number类似的开窗函数进行分页处理,此时如果遭遇挖坟帖的情形可能就需要漫长的等待且消耗巨大.这里给大家介绍根据Row_number()特性采用特定锁Hint提升查询速度.

直接上菜

脚本环境可在SQL Server优化技巧之SQL Server中的"MapReduce"找到

如下查询在分页中比较常见

set statistics time on
 
 select * from 
(
select ProductID, rn = ROW_NUMBER() OVER (ORDER BY ProductID)
from [bigTransactionHistory]
) as t
where t.rn between 15631801 and 15631802

这条查询在我的电脑上执行了15S,这还是数据全在内存中的情形!如图1-1

一个简单的执行计划执行如此之长有点匪夷所思,毕竟逻辑读才6W多,且无物理读

,而且CPU时间与占用时间相差无几,排除了阻塞之类的因素后我们把消耗定位在这个查询本身上.这时提一个Row_number()的特点,它可在万千数据中将其序列化让我们找到我们想要的精确数据点,但就此默认的实现方式上是为每一行数据都加一个行锁.

我们开启Trace Flag 1200再次执行语句捕捉下执行时的锁.可以看到Row_number()在实现上未进行锁升级如图1-2

dbcc traceon(3604,1200,-1)

select * from 
(
select ProductID, rn = ROW_NUMBER() OVER (ORDER BY ProductID)
from [bigTransactionHistory]
) as t
where t.rn between 15631801 and 15631802

到此我们对此问题的解决方式也就出来了:可采用锁hint的形式手动为其升级

这里我采用页锁,如图1-3

而两者从执行计划上看是相同的,预估也完全一样如图1-4

select * from 
(
select ProductID, rn = ROW_NUMBER() OVER (ORDER BY ProductID)
from [bigTransactionHistory] with(paglock)
) as t
where t.rn between 15631801 and 15631802


可以看到我们通常的查看执行计划的方式在此就不太适合了,需要我们对资源消耗有更详细的认知.

注:平时我们还可用Trace Profiler捕捉锁,但需注意慎用.

Row_number()默认看不到锁升级,全局性能瓶颈下可能回升级

如果你的应用不在乎脏读,nolock方式更愉快:)

其它:当数据被更新发生阻塞时,有时业务同事会问到底更新了哪条数据有木有?

这里写了个简单的查询以便找到具体更新被锁住的行,如图2-1

begin tran ttt
update dbo.[bigProduct] set size=111 where ProductID<1100
-- rollback when finish test
--rollback tran ttt

--open another session

SELECT * FROM [bigProduct] with(nolock)
WHERE
 %%LOCKRES%% IN
 (
 SELECT 
 tl.resource_description
 FROM sys.dm_tran_locks AS tl
 INNER JOIN sys.partitions AS t2 ON
 t2.hobt_id = tl.resource_associated_entity_id
 WHERE 
 t2.object_id = OBJECT_ID('bigProduct')
 AND tl.resource_type = 'KEY'
 )

结语:系统内任何元素都有可能成为影响平衡的绊脚石.找到它,理解它,利用它.

下载本文
显示全文
专题