我刚刚看了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) 我遇到过一种情况,用户在我们的一个运行存储过程的应用程序中运行了某些内容。存储过程执行一些日志记录(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 想要运行一个查询,而该查询被授予的内存多于实例可用的内存,会发生什么情况。我最初的想法是我可能会看到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(通过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) 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 系统(安装 Windows 更新后)。
在过去的三周里,我看到 SQL Server 服务在服务器恢复时没有启动(配置管理器显示该服务已停止),系统事件日志显示以下错误:
事件 ID 7000
由于以下错误,SQL Server (MSSQLSERVER) 服务无法启动:该服务没有及时响应启动或控制请求。
事件 ID 7001
SQL Server 代理 (MSSQLSERVER) 服务依赖于由于以下错误而无法启动的 SQL Server (MSSQLSERVER) 服务:该服务没有及时响应启动或控制请求。
事件 7009
由于以下错误,SQL Server (MSSQLSERVER) 服务无法启动:该服务没有及时响应启动或控制请求。
但是,我可以手动启动该服务并且它可以正常启动。
该服务设置为自动启动。
不幸的是,SQL Server 错误日志也不包含任何线索。
我有一个 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 的事务日志,现在已经实施了定期日志备份以防止这个级别的增长
我的数据库中有一些自动生成的 _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 统计信息在运行查询时更新,将使用它们并且它们已过时?
当 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 返回的错误信息是:'无法检索 …
使用 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 ×8
blocking ×1
checkpoint ×1
deadlock ×1
index ×1
memory-grant ×1
performance ×1
powershell ×1
shrink ×1
statistics ×1