SQL Server:如何针对表向每个查询添加提示?

时间:2014-08-15 05:58:10

标签: sql sql-server

我有一个交易数据库。其中一张桌几乎是空的(A)。它有一个唯一的索引列(x),没有聚簇索引。

2个并发交易:

begin trans
insert into A (x,y,z) (1,2,3)
WAITFOR DELAY '00:00:02'; -- or manually run the first 2 lines only
select * from A where x=1; -- small tables produce a query plan of table scan here, and block against the transaction below.
commit

begin trans
insert into A (x,y,z) (2,3,4)
WAITFOR DELAY '00:00:02';
-- on a table with 3 or less pages this hint is needed to not block against the above transaction
select * from A with(forceseek) -- force query plan of index seek + rid lookup
    where x=2;
commit

我的问题是,当表有很少的行时,2个事务可以死锁,因为SQL Server为select生成表扫描,即使有索引,并且两个都等待新插入的行持有的锁另一笔交易。

当此表中有很多行时,查询计划会更改为索引搜索,并且两者都很乐意完成。

当表格很小时,WITH(FORCESEEK)提示会强制执行正确的查询计划(对于小表格来说要贵5%)。

  1. 是否可以为表格上的所有查询提供默认提示,假装有'forceseek'提示?

  2. 上面的死锁代码是由Hibernate生成的,是否有可能让hibernate发出所需的查询提示?

  3. 我们可以使表格假装足够大,以便查询优化器选择UPDATE STATISTICS http://msdn.microsoft.com/en-AU/library/ms187348(v=sql.110).aspx中未记录的功能的索引搜索。任何人都可以看到使所有少于1000行的表假装他们在10页上有1000行的任何缺点吗?

3 个答案:

答案 0 :(得分:4)

您可以创建Plan Guide

或者您可以在数据库中启用Read Committed Snapshot隔离级别。

更好的是:使索引聚集。

对于经历高更新率的小型表,也许您可​​以应用Using tables as Queues的建议。

  

任何人都可以看到使所有少于1000行的表假装他们在10页上有1000行的任何缺点吗?

如果该表出现在另一个更复杂的查询(思考联接)中,那么基数估计值可能会大幅下降并产生错误的计划。

答案 1 :(得分:3)

您可以创建一个视图,该视图是表的副本,但使用提示并让查询使用该视图:

create view A2 as
select * from A with(forceseek)

如果要保留查询使用的表名,请将表重命名为其他名称,然后将视图命名为" A":

sp_rename 'A', 'A2';
create view A as
select * from A2 with(forceseek)

答案 2 :(得分:0)

只需添加另一个您可以考虑的选项。

您可以使用

锁定整个表格
ALTER TABLE MyTable SET LOCK_ESCALATION = TABLE

如果您没有太多会排队并降低性能的更新,则此解决方法很好。

它是表格范围的,不需要更新其他代码。