标签: sql-server

使用 RECOMPILE 查询提示时查询之间的执行时间存在巨大差异

我有两个几乎相同的查询在同一个 SQL Server 2005 实例上运行:

  1. 第一个是SELECT由 LINQ 生成的原始查询(我知道,我知道......我不是应用程序开发人员,只是 DBA :)。
  2. 第二个和第一个完全一样,OPTION (RECOMPILE)在最后加了一个。

没有其他任何改变。

第一个每次运行需要 55 秒。
第二个需要 2 秒。

两个结果集是相同的。

为什么这个提示会产生如此显着的性能提升?

在线图书条目RECOMPILE没有提供非常详细的解释:

指示 SQL Server 数据库引擎在执行后放弃为查询生成的计划,强制查询优化器在下次执行相同查询时重新编译查询计划。在不指定 RECOMPILE 的情况下,数据库引擎会缓存查询计划并重用它们。编译查询计划时,RECOMPILE 查询提示使用查询中任何局部变量的当前值,如果查询在存储过程中,则将当前值传递给任何参数。

RECOMPILE 是创建使用 WITH RECOMPILE 子句的存储过程的一种有用的替代方法,当必须重新编译存储过程中的查询子集而不是整个存储过程时。有关详细信息,请参阅重新编译存储过程。RECOMPILE 在您创建计划指南时也很有用。有关更多信息,请参阅使用计划指南优化已部署应用程序中的查询。

由于我的查询有很多局部变量,我的猜测是当我使用OPTION (RECOMPILE)查询提示时,SQL Server 能够(认真地)优化它。

我所看到的每个地方都有人说OPTION (RECOMPILE)应该避免这种情况。对此的解释通常是使用此提示 SQL Server 无法重用此执行计划,因此每次都必须浪费时间重新编译它。
(但是)考虑到巨大的性能优势,我倾向于认为这次使用这个查询提示会是一件好事。

我应该使用它吗?如果没有,有没有一种方法可以强制 SQL Server 使用更好的执行计划而无需此提示且无需更改应用程序?

performance sql-server-2005 sql-server optimization query-performance

16
推荐指数
1
解决办法
2429
查看次数

在哪里学习 SQL Server Service Broker?

是否有学习 Service Broker 的好资源?我正在寻找对新手友好的指南。

sql-server service-broker sql-server-2012

16
推荐指数
2
解决办法
2372
查看次数

Transaction Log 不会收缩,DB 认为它在复制

我有一个运行 Kaspersky Security Center 的 SQL Server 2008 R2 Express 数据库,我不知道安装是在什么情况下发生的,但数据库似乎认为它正在被复制并且不会从事务日志中释放任何空间。例如:

USE master;

SELECT 
    name, log_reuse_wait, log_reuse_wait_desc, is_cdc_enabled 
FROM 
    sys.databases 
WHERE 
    name = 'KAV';

SELECT DATABASEPROPERTYEX('KAV', 'IsPublished');
Run Code Online (Sandbox Code Playgroud)

返回:

name | log_reuse_wait | log_reuse_wait_desc | is_cdc_enabled
-----|----------------|---------------------|---------------
KAV  | 6              | REPLICATION         | 0 
Run Code Online (Sandbox Code Playgroud)
DATABASEPROPERTYEX('KAV', 'IsPublished')
----------------------------------------
0 [not published]
Run Code Online (Sandbox Code Playgroud)

ReplicationSSMS的部分中也没有列出任何内容。

到目前为止,我已经尝试了从 Google 结果中收集到的几个语句:

USE KAV;
EXEC sp_repldone null, null, 0,0,1;
EXEC sp_removedbreplication KAV;
Run Code Online (Sandbox Code Playgroud)

但是我没有运气让这个数据库停止认为它正在被复制。

完整sys.databases信息:

USE master;

SELECT 
    name, log_reuse_wait, log_reuse_wait_desc, is_cdc_enabled 
FROM 
    sys.databases 
WHERE 
    name = …
Run Code Online (Sandbox Code Playgroud)

replication sql-server transaction-log

16
推荐指数
2
解决办法
2万
查看次数

SQL Server 索引更新死锁

我有 2 个查询,当同时运行时会导致死锁。

查询 1 - 更新包含在索引 (index1) 中的列:

update table1 set column1 = value1 where id = @Id
Run Code Online (Sandbox Code Playgroud)

在 table1 上使用 X-Lock,然后在 index1 上尝试 X-Lock。

查询 2:

select columnx, columny, etc from table1 where {some condition}
Run Code Online (Sandbox Code Playgroud)

在 index1 上使用 S-Lock,然后在 table1 上尝试 S-Lock。

有没有办法在保持相同查询的同时防止死锁?例如,我可以在更新之前以某种方式在更新事务中的索引上使用 X-Lock 以确保表和索引访问的顺序相同 - 这应该防止死锁?

隔离级别为 Read Committed。为索引启用了行锁和页锁。同一个记录可能同时参与了两个查询 - 我无法从死锁图中判断出来,因为它没有显示参数。

死锁图

sql-server deadlock locking

16
推荐指数
1
解决办法
9871
查看次数

可以对 SQL Server 系统表进行碎片整理吗?

我们有几个数据库,其中创建和删除了大量表。据我们所知,SQL Server 不对系统基表进行任何内部维护,这意味着它们会随着时间的推移变得非常碎片化并变得臃肿。这会给缓冲池带来不必要的压力,也会对计算数据库中所有表的大小等操作的性能产生负面影响。

有没有人建议尽量减少这些核心内部表上的碎片?一个明显的解决方案可以避免创建如此多的表(或在 tempdb 中创建所有临时表),但对于这个问题,我们假设应用程序没有这种灵活性。

编辑:进一步的研究显示了这个悬而未决的问题,它看起来密切相关,并表明某种形式的手动维护ALTER INDEX...REORGANIZE可能是一种选择。


初步研究

可以在以下位置查看有关这些表的元数据sys.dm_db_partition_stats

-- The system base table that contains one row for every column in the system
SELECT row_count,
    (reserved_page_count * 8 * 1024.0) / row_count AS bytes_per_row, 
    reserved_page_count/128. AS space_mb
FROM sys.dm_db_partition_stats
WHERE object_id = OBJECT_ID('sys.syscolpars')
    AND index_id = 1
-- row_count:       15,600,859
-- bytes_per_row:   278.08
-- space_mb:        4,136
Run Code Online (Sandbox Code Playgroud)

但是,sys.dm_db_index_physical_stats似乎不支持查看这些表的碎片:

-- No fragmentation data is returned by sys.dm_db_index_physical_stats
SELECT *
FROM …
Run Code Online (Sandbox Code Playgroud)

sql-server fragmentation system-tables sql-server-2014

16
推荐指数
2
解决办法
3936
查看次数

将存储过程的结果插入到表变量中

我有一个将值存储在表变量中的存储过程。我选择这些值并在调用过程时返回它们。

我试图在另一个表变量中设置这些返回值,但我无法弄清楚。

存储过程

ALTER PROCEDURE [dbo].[GetOrSetDomainId]
@DomainName varchar(50),
@DomainUrl varchar(50)
AS
BEGIN
    DECLARE @DomainId bigint;
    DECLARE @NumberOfRwos bigint;

    DECLARE @DomainHistory TABLE
    (
        DomainId bigint, 
        HasHistory bit,
        ServerOnline bit,
        DatabaseOnline bit, 
        ServerPerformance bigint,
        DatabasePerformance bigint, 
        SoldTickets bigint
    )


    SELECT  @NumberOfRwos =  COUNT(Id) 
    FROM DomainData
    WHERE DomainName = @DomainName OR DomainUrl = @DomainUrl

    IF(@NumberOfRwos = 0)
    BEGIN
        INSERT INTO DomainData (DomainName, DomainUrl) VALUES (@DomainName, @DomainUrl)

         SELECT @DomainId =  @@IDENTITY

         INSERT INTO @DomainHistory(DomainId,HasHistory)VALUES(@DomainId, 0)

         SELECT * FROM @DomainHistory
    END

    ELSE
    BEGIN
    ---not important …
Run Code Online (Sandbox Code Playgroud)

sql-server stored-procedures t-sql temporary-tables

16
推荐指数
1
解决办法
6万
查看次数

由于 WHERE 子句中有超过 100,000 个条目,SQL Server 错误 8632

我的问题(或至少是错误消息)与查询处理器耗尽内部资源非常相似- 非常长的 sql query

我的客户正在使用 SQL 选择查询,其中包含一个恰好包含 100,000 个条目的 where 子句。

查询失败,错误 8632 和错误消息

内部错误:已达到表达式服务限制。请在您的查询中寻找潜在的复杂表达式,并尝试简化它们。)

我发现抛出此错误消息非常奇怪,正好是 100,000 个条目,所以我想知道这是否是一个可配置的值。是这种情况吗?如果是,我怎样才能将此值增加到更高的值?

MSDN 上,有人提议重新编写查询,但我想避免这种情况。

同时我发现我正在谈论的条目列表包含自然数,其中相当一部分似乎是连续的(例如 (1,2,3,6,7,8,9,10,12, 13、15、16、17、18、19、20)。

这使得 SQL where 子句类似于:

where entry in (1,2,3,6,7,8,9,10,12,13,15,16,17,18,19,20)
Run Code Online (Sandbox Code Playgroud)

我可以将其转换为:

where (entry between 1 and 3) OR
      (entry between 6 and 10) OR
      (entry between 12 and 13) OR
      (entry between 15 and 20)
Run Code Online (Sandbox Code Playgroud)

可以通过以下方式缩短:

where entry in (1,...,3,6,...,10,12,13,15,...,20)
Run Code Online (Sandbox Code Playgroud)

......或类似的东西?(我知道这是一个长镜头,但它会使软件更新更容易和更易读)

供您参考: where 子句中的数据是在另一个表上完成的计算结果:首先在开始时读取并过滤该表的条目,然后进行一些额外的处理(这是不可能使用的SQL),额外处理的结果是更多的过滤,并且结果用于 where 子句中。由于无法在 SQL 中编写完整的过滤,因此使用了上述方法。显然, where 子句的内容可能会在每次处理时发生变化,因此需要动态解决方案。

sql-server configuration limits

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

重建超大主键索引

我有一个托管在 Azure 上的 SQL 数据库。问题是大小越来越失控,我可以在主键聚集索引中看到高达 99% 的碎片。

我可以使用online=on选项重建所有其他索引,并且不会影响性能。PK Clustered 索引之一的大小大于 200GB,因此 aREBUILD...WITH (ONLINE=ON)会导致锁定。

我们确实有来自所有时区的用户访问该站点,所以真的,我无法找到可以离线重建索引的时间。

在站点不停机的情况下重建大型索引的最佳策略是什么?

我相信重组无济于事,因为碎片化是 99%。问题是即使在线,表也会被锁定。主要问题是索引大于200GB。主键是一个整数。

sql-server clustered-index index-tuning azure-sql-database

16
推荐指数
2
解决办法
1万
查看次数

SQL Server 在插入时更改 XML 结构

我正在将一些 XML 数据插入 SQL Server 中的 XML 列,但在插入数据后,它已被 sql server 更改。这是我插入的数据

              <xsl:value-of select="name/n/given" />
            <xsl:text> </xsl:text>
          <xsl:value-of select="name/n/family" />
Run Code Online (Sandbox Code Playgroud)

当我读回来时,它看起来像这样

              <xsl:value-of select="name/n/given" />
          <xsl:text />
          <xsl:value-of select="name/n/family" />
Run Code Online (Sandbox Code Playgroud)

注意第二行。这是一个问题,因为它改变了 XSLT 转换输出的方式。第一个例子将在给定和姓氏之间创建一个空格,而第二个不会创建任何空格,所以它会像约翰约翰森,而第一个会像约翰约翰森。

有没有办法解决这个问题?

xml sql-server

16
推荐指数
2
解决办法
2114
查看次数

使用比必要大得多的列大小

我正在与其他人一起创建 SQL Server 数据库。其中一个表很小(6 行),其中的数据可能会保持不变。添加新行的可能性很小。该表看起来像这样:

CREATE TABLE someTable (
    id int primary key identity(1,1) not null,
    name varchar(128) not null unique
    );
INSERT INTO someTable values ('alice', 'bob something', 'charles can dance', 'dugan was here');
Run Code Online (Sandbox Code Playgroud)

我正在查看该name列的字符长度,我认为它的值可能永远不会大于 32 个字符,甚至可能不会大于 24。我将此列更改为,有什么好处,例如,varchar(32)

另外,将默认列大小保持为 4、8、32 等的倍数有什么好处吗?

database-design sql-server varchar

16
推荐指数
2
解决办法
2144
查看次数