小编SEa*_*986的帖子

创建未被 (SELECT) 查询使用的索引会降低该查询的性能

我刚刚看了Pinal Dave 的这个视频

他有一个SELECT查询,它在 tempdb 中产生 ~370k 读取和 ~1200 读取查询所SELECT来自的表。

然后他创建了一个索引(我们称之为,Index1),它删除了 tempdb 假脱机,从而提高了查询的性能。到目前为止一切正常。

然而,他随后创建了一个进一步的索引(我们称之为Index2)并Index1保持原样。

然后他再次运行他的查询,尽管Index2没有被使用,但查询性能恢复到原来的状态,~370k tempdb spool 仍然存在。

他实际上似乎并没有描述导致这种情况的原因(除非我错过了)

要重现的代码如下(感谢 Martin Smith 提供 Pastebin)这假设 AdventureWorks 的 vanilla 版本,其标准索引位于 SalesOrderDetail

SET STATISTICS XML ON;
SET STATISTICS IO ON
GO

-- The query
DBCC FREEPROCCACHE;
SELECT SalesOrderID, ProductId,SalesOrderDetailID, OrderQty
FROM   Sales.SalesOrderDetail sod
WHERE  ProductID = (SELECT AVG(ProductID)
                    FROM   Sales.SalesOrderDetail sod1
                    WHERE  sod.SalesOrderID = sod1.SalesOrderID
                    GROUP  BY sod1.SalesOrderID);
/* …
Run Code Online (Sandbox Code Playgroud)

performance index sql-server

10
推荐指数
2
解决办法
755
查看次数

SQL Server 没有消除死锁吗?

我遇到过一种情况,用户在我们的一个运行存储过程的应用程序中运行了某些内容。存储过程执行一些日志记录(INSERT记录到日志表),然后以以下格式执行简单的删除

DELETE FROM MyTable WHERE Id = 1

从具有数百万行的表中删除DELETE数万条记录(存储过程对多个表执行此操作)并生成并行执行计划。Id 列是复合主键中的第二列,但该表没有任何以该列开头的索引。

删除计划可在此处获取

表的匿名 DDL 如下

CREATE TABLE [dbo].MyTable
(
    [Column15] [varchar](50) NULL,
    [Column16] [int] NULL,
    [Column2] [datetime] NULL,
    [Column3] [datetime] NULL,
    [Column4] [varchar](50) NOT NULL,
    [Column5] [datetime] NULL,
    [Column17] [varchar](8) NULL,
    [Column18] [varchar](50) NULL,
    [Column6] [int] NULL,
    [Column7] [int] NULL,
    [Column9] [int] NULL,
    [Column8] [int] NULL,
    [Column19] [varchar](50) NULL,
    [Column20] [varchar](50) NULL,
    [Column21] [varchar](50) NULL,
    [Column22] [varchar](50) NULL,
    [Column23] [varchar](50) NULL,
    [Column24] [varchar](50) NULL,
    [Column25] [varchar](50) …
Run Code Online (Sandbox Code Playgroud)

sql-server deadlock blocking sql-server-2016

10
推荐指数
0
解决办法
362
查看次数

SQL Server 是否可以为查询授予比实例可用的内存更多的内存

前几天有人问我,如果 SQL Server 想要运行一个查询,而该查询被授予的内存多于实例可用的内存,会发生什么情况。我最初的想法是我可能会看到RESOURCE_SEMAPHORE等待并且查询永远不会开始。

我做了一些测试来试图找出答案。

我的实例以 4000MB RAM 启动:

EXEC sys.sp_configure N'max server memory (MB)', N'4000'
GO
RECONFIGURE WITH OVERRIDE
GO
Run Code Online (Sandbox Code Playgroud)

如果我然后运行我的(故意可怕的)查询:

USE StackOverflow
SELECT      CONVERT(NVARCHAR(4000), u.DisplayName) AS DisplayName,
            CONVERT(NVARCHAR(MAX), u.DisplayName) AS Disp2,
            CONVERT(NVARCHAR(MAX), u.DisplayName) AS Disp3
FROM        dbo.Users AS u
            JOIN dbo.Posts p
                ON LTRIM(u.DisplayName) = LTRIM(p.Tags)
WHERE       u.CreationDate >= '2008-12-25'
            AND u.CreationDate < '2010-12-26'
ORDER BY    u.CreationDate;
Run Code Online (Sandbox Code Playgroud)

执行计划显示授予的内存为 732,008KB。

然后,我将实例可用的内存设置为低于此数字,然后重新启动实例:

EXEC sys.sp_configure N'max server memory (MB)', N'500' /* a value lower than the previous memory …
Run Code Online (Sandbox Code Playgroud)

sql-server database-internals sql-server-2019 memory-grant

10
推荐指数
1
解决办法
2326
查看次数

如果系统在下一个检查点之前出现故障,脏页会发生什么?

假设一个数据库使用完全恢复模式,当一条记录写入SQL Server(通过INSERT/ UPDATEetc)时,预写日志将确保在修改数据页之前将更改写入日志文件。

日志和数据页条目都在 RAM 中创建,稍后通过检查点提交到磁盘。

如果系统崩溃(为了论证而断电),脏页(在 RAM 中更改但未提交到磁盘的 IE 数据)会发生什么,因为 RAM 的内容无法在系统重新启动后幸存下来,这些数据是否丢失?

编辑

经过一些测试,我可以看到脏页没有丢失,但我不确定为什么:

使用本教程

创建一个测试数据库

CREATE DATABASE DirtyPagesDB
GO
USE DirtyPagesDB
GO
Run Code Online (Sandbox Code Playgroud)

关闭自动检查点

DBCC TRACEON(3505, -1);
DBCC TRACESTATUS();
Run Code Online (Sandbox Code Playgroud)

创建一个表,插入一些数据并发出一个检查点:

CREATE TABLE t1 (Speaker_Bio CHAR(8000))
GO
INSERT INTO t1 VALUES ('SQL'),('Authority')
GO
CHECKPOINT
Run Code Online (Sandbox Code Playgroud)

确认没有脏页

-- Get the rows of dirtied pages
SELECT
database_name = d.name,
OBJECT_NAME =
CASE au.TYPE
WHEN 1 THEN o1.name
WHEN 2 THEN o2.name
WHEN 3 THEN o1.name
END,
OBJECT_ID =
CASE …
Run Code Online (Sandbox Code Playgroud)

sql-server checkpoint

9
推荐指数
1
解决办法
1154
查看次数

sp_msforeach db - 为什么我们需要使用 USE 关键字

sp_msforeachdb是一个未公开的 sp,旨在针对服务器实例中的每个数据库运行一些 T-SQL。那么,为什么我需要使用USE关键字来做到这一点

EXEC sp_MSForEachDb @command1 = 'SELECT DB_NAME()'
Run Code Online (Sandbox Code Playgroud)

打印sp_MSForEachDb命令对n次运行的数据库名称,其中n是实例上的数据库数。

EXEC sp_MSForEachDb @command1 = 'USE ?; SELECT DB_NAME()'
Run Code Online (Sandbox Code Playgroud)

打印每个数据库的名称。

为什么需要使用USE语句?这种行为不应该是程序中固有的吗?

sql-server stored-procedures

8
推荐指数
2
解决办法
1233
查看次数

系统重启后 SQL Server 服务未自动启动

我有一个每周重新启动的 SQL Server 系统(安装 Windows 更新后)。

在过去的三周里,我看到 SQL Server 服务在服务器恢复时没有启动(配置管理器显示该服务已停止),系统事件日志显示以下错误:

事件 ID 7000

由于以下错误,SQL Server (MSSQLSERVER) 服务无法启动:该服务没有及时响应启动或控制请求。

事件 ID 7001

SQL Server 代理 (MSSQLSERVER) 服务依赖于由于以下错误而无法启动的 SQL Server (MSSQLSERVER) 服务:该服务没有及时响应启动或控制请求。

事件 7009

由于以下错误,SQL Server (MSSQLSERVER) 服务无法启动:该服务没有及时响应启动或控制请求。

但是,我可以手动启动该服务并且它可以正常启动。

该服务设置为自动启动。

不幸的是,SQL Server 错误日志也不包含任何线索。

sql-server windows-server sql-server-2014

8
推荐指数
1
解决办法
7016
查看次数

为什么我不能在完全恢复模式下缩小日志文件

我有一个 302MB 的日志文件。

我做了一个日志备份,它使日志文件大部分都是免费的(我可以通过磁盘使用标准报告看到这一点)

如果我试着跑

DBCC SHRINKFILE (N'AdventureWorks2014_Log' , 0, TRUNCATEONLY)
Run Code Online (Sandbox Code Playgroud)

或者

DBCC SHRINKFILE (N'AdventureWorks2014_Log' , 0)
Run Code Online (Sandbox Code Playgroud)

该文件仍显示为 302MB。

我知道我可以将数据库更改为简单恢复,然后运行上述命令之一并设置回完全恢复(然后进行完全备份以确保数据库未处于伪简单恢复模式

但是,为什么我不能在完全恢复模式下缩小文件?

我知道收缩不是你应该做的事情,但在我现实世界的数据库中,因为没有人备份过它已经增长到 30GB 的事务日志,现在已经实施了定期日志备份以防止这个级别的增长

sql-server shrink transaction-log recovery-model

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

_WA_Sys_ 统计何时更新?

我的数据库中有一些自动生成的 _WA_Sys_ 统计信息,它们有一段时间没有更新(与同一个表中的其他统计信息相比)

经验法则似乎是在大于 500 行的表中,统计信息在 20% + 500 行数据更改时更新。

但是,我可以看到使用以下查询

SELECT  t.name,
        i.name,
        i.rowcnt,
        i.rowmodctr,
        p.last_updated
FROM    sys.sysindexes i
        JOIN sys.tables t
            ON i.id = t.object_id
        JOIN sys.stats s
            ON s.object_id = t.object_id AND i.name = s.name
        CROSS APPLY sys.dm_db_stats_properties(s.object_id,s.stats_id) p
WHERE   rowmodctr > 0
ORDER BY i.rowmodctr DESC
Run Code Online (Sandbox Code Playgroud)

有一个表包含许多过时的 _WA_Sys_ 统计信息(并且 rowmodctr 高于 20% + 500)

如果对表运行查询并在 WHERE 子句中添加与过时 _WA_Sys_ 统计信息关联的列之一并检查统计信息的更新日期,我可以看到它已更新。

如果我再次使用 WHERE 子句运行相同的查询,则统计信息不会更新

似乎 _WA_Sys 统计信息在运行查询时更新,将使用它们并且它们已过时?

statistics sql-server-2014 cardinality-estimates

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

以管理员身份从代理运行 Powershell 脚本

当 SQL Server 服务启动时,我需要在我的服务器上的 IIS 中回收一个 AppPool。

我采取的路线是有一个启动存储过程,它运行具有 Powershell 作业步骤的代理作业。

我已经从互联网上创建/抓取了一个 Powershell 脚本来回收应用程序池:

# Load IIS module:
Import-Module WebAdministration
# Set a name of the site we want to recycle the pool for:
$site = "Default Web Site"
# Get pool name by the site name:
$pool = (Get-Item "IIS:\Sites\$site"| Select-Object applicationPool).applicationPool
# Recycle the application pool:
Restart-WebAppPool $pool
Run Code Online (Sandbox Code Playgroud)

这适用于操作系统级别,但仅当 Powershell 以管理员身份运行时才有效(即使我在 Admin 组中登录到 Windows 的帐户也是如此)

果然,如果我使用包含上述代码的 Powershell 步骤在代理中创建作业,则在执行时会出现错误

作业步骤在 PowerShell 脚本的第 6 行收到错误。对应的行是'$pool = (Get-Item "IIS:\Sites\$site"| Select-Object applicationPool).applicationPool'。更正脚本并重新安排作业。PowerShell 返回的错误信息是:'无法检索 …

powershell windows-server sql-server-2014

7
推荐指数
2
解决办法
4063
查看次数

为什么对索引列的不等式搜索会给出恒定的扫描

使用 StackOverflow2010 数据库,我可以在 users 表上创建索引,如下所示:

CREATE INDEX IX_DisplayName ON dbo.Users
(
    DisplayName,
    UpVotes
)
Run Code Online (Sandbox Code Playgroud)

然后对索引的键运行不等式搜索:

SELECT  DisplayName,
        UpVotes
FROM    Users
WHERE   DisplayName <> N'Alex'
Run Code Online (Sandbox Code Playgroud)

我在这里得到计划

我正在尝试弄清楚 SQL Server 如何获取此查询的结果。

该计划从一些持续扫描开始,但输出列表是空白的,因此我不清楚它们的用途。

然后,每个恒定扫描进入一个计算标量,每个计算标量输出

Compute Scalar Node6
Expr1002 = 10
Expr1003 = NULL
Expr1004 = N'Alex'

Compute Scalar Node9 
Expr1005 = 6 
Expr1006 = N'Alex' 
Expr1007 = NULL
Run Code Online (Sandbox Code Playgroud)

然后,连接运算符似乎连接了上面的一些输出:

Expr1010 = Expr1008,Expr1006
Expr1011 = Expr1004,Expr1009
Expr1012 = Expr1002,Expr1005
Run Code Online (Sandbox Code Playgroud)

但它有我在计划中看不到的输入(Expr 1008 和 Expr1009)

我也不知道为什么需要TOP N排序

索引搜索是有意义的 - 它正在寻找 > Expr1011 和 < Expr1012。我 …

sql-server execution-plan sql-server-2019 query-performance

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