小编i-o*_*one的帖子

MERGE 死锁预防

在我们的一个数据库中,我们有一个由多个线程密集并发访问的表。线程确实通过MERGE. 还有一些线程偶尔会删除行,因此表数据非常不稳定。执行 upsert 的线程有时会陷入死锁。该问题看起来与问题中描述的问题相似。不过,不同之处在于,在我们的例子中,每个线程都只更新或插入一行

简化设置如下。该表是堆,上面有两个唯一的非聚集索引

CREATE TABLE [Cache]
(
    [UID] uniqueidentifier NOT NULL CONSTRAINT DF_Cache_UID DEFAULT (newid()),
    [ItemKey] varchar(200) NOT NULL,
    [FileName] nvarchar(255) NOT NULL,
    [Expires] datetime2(2) NOT NULL,
    CONSTRAINT [PK_Cache] PRIMARY KEY NONCLUSTERED ([UID])
)
GO
CREATE UNIQUE INDEX IX_Cache ON [Cache] ([ItemKey]);
GO
Run Code Online (Sandbox Code Playgroud)

典型的查询是

DECLARE
    @itemKey varchar(200) = 'Item_0F3C43A6A6A14255B2EA977EA730EDF2',
    @fileName nvarchar(255) = 'File_0F3C43A6A6A14255B2EA977EA730EDF2.dat';

MERGE INTO [Cache] WITH (HOLDLOCK) T
USING (
    VALUES (@itemKey, @fileName, dateadd(minute, 10, sysdatetime()))
) S(ItemKey, FileName, Expires)
ON …
Run Code Online (Sandbox Code Playgroud)

sql-server deadlock execution-plan merge

15
推荐指数
1
解决办法
7463
查看次数

恒定扫描假脱机

我有一张有几十行的桌子。简化设置如下

CREATE TABLE #data ([Id] int, [Status] int);

INSERT INTO #data
VALUES (100, 1), (101, 2), (102, 3), (103, 2);
Run Code Online (Sandbox Code Playgroud)

我有一个查询将这个表连接到一组表值构造的行(由变量和常量组成),比如

DECLARE @id1 int = 101, @id2 int = 105;

SELECT
    COALESCE(p.[Code], 'X') AS [Code],
    COALESCE(d.[Status], 0) AS [Status]
FROM (VALUES
        (@id1, 'A'),
        (@id2, 'B')
    ) p([Id], [Code])
    FULL JOIN #data d ON d.[Id] = p.[Id];
Run Code Online (Sandbox Code Playgroud)

查询执行计划显示优化器的决定是使用FULL LOOP JOIN策略,这似乎是合适的,因为两个输入都有很少的行。但是,我注意到(并且不能同意)的一件事是正在假脱机的 TVC 行(请参阅红色框中的执行计划区域)。

恒定扫描假脱机

为什么优化器在这里引入spool,这样做的原因是什么?除了线轴没有什么复杂的。看起来是没有必要的。在这种情况下如何摆脱它,可能的方法是什么?


上述计划获得于

Microsoft SQL Server 2014 (SP2-CU11) (KB4077063) - 12.0.5579.0 (X64)

sql-server execution-plan

14
推荐指数
1
解决办法
1100
查看次数

恒定扫描应用

这个问题是关于VALUES这里这里开始的构造的优化器行为探索的延续。我想问一下VALUESAPPLY这次。

使用CROSS APPLY别名作为需要在查询的各个部分中引用的表达式是常见的模式。例如:

CREATE TABLE #data (N int);
INSERT INTO #data VALUES (5), (4), (3), (2), (1);

SELECT d.N, c.[Square]
FROM #data d
    CROSS APPLY (VALUES (d.N * d.N)) c([Square])
WHERE c.[Square] BETWEEN 1 AND 10
ORDER BY c.[Square];
Run Code Online (Sandbox Code Playgroud)

我自己总是CROSS APPLY在这种情况下使用,但有时我会遇到包裹在 inline-TVF 和OUTER APPLY-ed 中的此类表达式。因此,出于好奇,我换CROSSOUTER的exampling查询

SELECT d.N, c.[Square]
FROM #data d
    OUTER APPLY (VALUES (d.N * d.N)) c([Square])
WHERE c.[Square] …
Run Code Online (Sandbox Code Playgroud)

sql-server optimization database-internals

14
推荐指数
1
解决办法
362
查看次数

用于并行索引扫描的 STATISTICS IO

假设有一个带有聚集索引的表

create table [a_table] ([key] binary(900) unique clustered);
Run Code Online (Sandbox Code Playgroud)

和一些数据

insert into [a_table] ([key])
select top (1000000) row_number() over (order by @@spid)
from sys.all_columns a cross join sys.all_columns b;
Run Code Online (Sandbox Code Playgroud)

通过检查该表的存储统计

select st.index_level, page_count = sum(st.page_count)
from sys.dm_db_index_physical_stats(
    db_id(), object_id('a_table'), NULL, NULL, 'DETAILED') st
group by rollup (st.index_level)
order by grouping_id(st.index_level), st.index_level desc;
Run Code Online (Sandbox Code Playgroud)

有人能看见

index_level page_count
----------- ----------
8           1
7           7
6           30
5           121
4           487
3           1952
2           7812
1           31249
0           125000
NULL        166659
Run Code Online (Sandbox Code Playgroud)

该表总共需要 166659 页。

然而表扫描 …

sql-server parallelism database-internals sql-server-2014 scan

7
推荐指数
1
解决办法
416
查看次数

恒定扫描加入

在准备我之前的Constant Scan 问题时,我VALUES以各种方式进行了试验,并遇到了关于连接的事情,VALUES这对我来说很奇怪。

设置很简单

CREATE TABLE #data ([Id] int);
INSERT INTO #data VALUES (101), (103);
Run Code Online (Sandbox Code Playgroud)

然后有一个查询

DECLARE @id1 int = 101, @id2 int = 102;

SELECT *
FROM (VALUES (@id1), (@id2)) p([Id])
    FULL HASH JOIN #data d ON d.[Id] = p.[Id];
Run Code Online (Sandbox Code Playgroud)

没有什么特别之处。如果你运行它,它会工作并产生它的结果。这是它的执行计划

恒扫描加盟计划

VALUES然而删除行

SELECT *
FROM (VALUES (@id1)) p([Id])
    FULL HASH JOIN #data d ON d.[Id] = p.[Id];
Run Code Online (Sandbox Code Playgroud)

导致优化器失败

消息 8622,级别 16,状态 1,第 1 行
查询处理器无法生成查询计划...

为什么?有没有办法(除了将参数放入临时表)使用哈希算法使其工作?

注意:这不是真正的设备,用于研究优化器行为和功能。


上面的例子在

Microsoft SQL …

sql-server optimization database-internals

5
推荐指数
1
解决办法
381
查看次数

堆和聚集索引的统计 IO 差异

假设我们有两个包含数据的表:

create table heap (value int);
create table clust (value int primary key);
insert into heap values (1);
insert into clust values (1);
Run Code Online (Sandbox Code Playgroud)

通过检查他们的存储统计

select obj.name, st.alloc_unit_type_desc, st.index_level, st.page_count
from (values ('heap'), ('clust')) obj(name)
    join sys.indexes ix on ix.object_id = object_id(obj.name)
    cross apply sys.dm_db_index_physical_stats(
        db_id(), ix.object_id, ix.index_id, NULL, 'DETAILED') st;

select obj.name, au.total_pages, au.used_pages, au.data_pages
from (values ('heap'), ('clust')) obj(name)
    join sys.indexes ix on ix.object_id = object_id(obj.name)
    join sys.partitions p on p.object_id = ix.object_id and p.index_id = ix.index_id
    join sys.allocation_units …
Run Code Online (Sandbox Code Playgroud)

sql-server sql-server-2008-r2 sql-server-2014

4
推荐指数
1
解决办法
608
查看次数

模拟用户或登录映射到证书

假设在数据库中创建了一个证书

create certificate certName
    with subject = 'subj';
GO
Run Code Online (Sandbox Code Playgroud)

和映射到此证书的用户

create user userName
    from certificate certName;
GO
Run Code Online (Sandbox Code Playgroud)

试图直接冒充此用户

execute as user = 'userName';
GO
Run Code Online (Sandbox Code Playgroud)

execute as在模块的子句中指定用户

create procedure procName
with execute as 'userName'
as
    set nocount on;
GO
Run Code Online (Sandbox Code Playgroud)

返回错误

消息 15517,级别 16,状态 1 ...
无法作为数据库主体执行,因为主体“userName”不存在、无法模拟此类主体或您没有权限。

但是,我找不到文档中提到的这个限制(这里这里),唯一相关的声明似乎是

user_name 必须存在于当前数据库中并且必须是单例帐户。user_name 不能是组、角色、证书、密钥或内置帐户,例如 NT AUTHORITY\LocalService、NT AUTHORITY\NetworkService 或 NT AUTHORITY\LocalSystem。

是否可以模拟映射到证书的用户(或登录)?

security sql-server signature certificate impersonation

4
推荐指数
1
解决办法
1963
查看次数