在我正在处理的一个 Web 应用程序中,所有数据库操作都是使用一些在实体框架 ORM 上定义的通用存储库进行抽象的。
但是,为了通用存储库的简单设计,所有涉及的表都必须定义一个唯一的整数(Int32在 C# 中,int在 SQL 中)。直到现在,这一直是桌上的PK,也是IDENTITY.
外键被大量使用,它们引用这些整数列。它们对于一致性和 ORM 生成导航属性都是必需的。
应用层通常会做以下操作:
SELECT * FROM tableUPDATE table SET Col1 = Val1 WHERE Id = IdValDELETE FROM table WHERE Id = IdValINSERT INTO table (cols) VALUES (...)不太频繁的操作:
BULK INSERT ... into table后跟 (*) 所有数据加载(以检索生成的标识符)DELETE FROM table where OtherThanIdCol = SomeValue …然而,许多年过去了,自从它被报道以来,有几个主要版本进入了市场。
问题: SQL Server 2017 是否提供任何机制来轻松找出此错误的根本原因?还是像大约 9 年前报告该问题时一样难以调查?
我主要是使用实体框架 ORM 的 .NET 开发人员。但是,因为我不想在使用 ORM时失败,所以我试图了解数据层(数据库)中发生了什么。基本上,在开发过程中,我启动分析器并检查代码的某些部分根据查询生成了什么。
如果我发现一些非常复杂的事情(ORM 甚至可以从相当简单的 LINQ 语句中生成糟糕的查询,如果编写不仔细)和/或繁重(持续时间、CPU、页面读取),我会将它放入 SSMS 并检查其执行计划。
它适用于我的数据库知识水平。但是, BULK INSERT 似乎是一种特殊的生物,因为它似乎不会产生 SHOWPLAN。
我将尝试说明一个非常简单的例子:
表定义
CREATE TABLE dbo.ImportingSystemFileLoadInfo
(
ImportingSystemFileLoadInfoId INT NOT NULL IDENTITY(1, 1) CONSTRAINT PK_ImportingSystemFileLoadInfo PRIMARY KEY CLUSTERED,
EnvironmentId INT NOT NULL CONSTRAINT FK_ImportingSystemFileLoadInfo REFERENCES dbo.Environment,
ImportingSystemId INT NOT NULL CONSTRAINT FK_ImportingSystemFileLoadInfo_ImportingSystem REFERENCES dbo.ImportingSystem,
FileName NVARCHAR(64) NOT NULL,
FileImportTime DATETIME2 NOT NULL,
CONSTRAINT UQ_ImportingSystemImportInfo_EnvXIs_TableName UNIQUE (EnvironmentId, ImportingSystemId, FileName, FileImportTime)
)
Run Code Online (Sandbox Code Playgroud)
注意:表上没有定义其他索引
批量插入 (我在探查器中捕获的内容,仅一批)
insert bulk [dbo].[ImportingSystemFileLoadInfo] ([EnvironmentId] …Run Code Online (Sandbox Code Playgroud) 我正在处理一个相当古老的 .NET 项目,并引入了一些新功能(在顶部),这些功能产生了以下副作用:所有生成的 SELECT(或组)都包含在BEGIN TRAN ... COMMIT语句中。
这听起来很愚蠢,但要摆脱它需要进行大量更改,而我负担不起。我的假设是这基本上意味着每组 SELECT 的小开销(应用程序和 SQL Server 之间的 BEGIN TRAN 和 COMMIT)。
我想知道是否还有更多内容(额外锁定?)。
问题:如果选择语句包含在 BEGIN TRAN ... COMMIT 中,是否有任何副作用?
我有一些叶表(对它们没有 FK),其中有几十万条记录,用于使用实体框架 ORM 同步一些外部数据。这涉及一些 DELETE,然后是 BULK INSERT。
对于大多数表,一些旧值可能会永远保留,所以我不能将 SEQUENCEs 与 CYCLE 一起使用,正如其中一条评论中所建议的那样。
一种影响是身份值会随着时间的推移不断增加,我希望能够降低它们的值。
这个问题及其答案解释了无法更新标识值,即使identity_insert表的标识值已打开。
一种快速的方法是将所有数据传输到缓冲表并通过重命名执行切换。类似于以下内容:
-- ActiveDirectoryCache_bak is the table I want to reduce identity values for
-- ActiveDirectoryCache_bak_buffer is a buffer table that will be renamed to ActiveDirectoryCache_bak once data transfer is ready
begin tran
select min(UserId), count(1) from ActiveDirectoryCache_bak
DBCC CHECKIDENT ('ActiveDirectoryCache_bak', NORESEED);
-- Min UserId = 100, Count = 176041
-- Checking identity information: current identity value '204558', current column value '204558'.
select * …Run Code Online (Sandbox Code Playgroud) 我正在开发一个应用程序,该应用程序具有多个严重依赖存储过程的遗留模块(没有 ORM,因此所有获取和数据持久性都是通过存储过程完成的)。
遗留模块的安全性依赖于SUSER_NAME()获取当前用户并应用安全规则。
我将其迁移为使用 ORM(实体框架),并且 SQL 连接器将使用通用用户连接到数据库(SQL Server),因此我必须向许多过程提供当前用户名。
为了避免 .NET 代码发生更改,我想到在建立新连接时以某种方式在上下文中“注入”当前用户:
CREATE TABLE dbo.ConnectionContextInfo
(
ConnectionContextInfoId INT NOT NULL IDENTITY(1, 1) CONSTRAINT PK_ConnectionContextInfo PRIMARY KEY,
Created DATETIME2 NOT NULL CONSTRAINT DF_ConnectionContextInfo DEFAULT(GETDATE()),
SPID INT NOT NULL,
AttributeName VARCHAR(32) NOT NULL,
AttributeValue VARCHAR(250) NULL,
CONSTRAINT UQ_ConnectionContextInfo_Info UNIQUE(SPID, AttributeName)
)
GO
Run Code Online (Sandbox Code Playgroud)
当连接打开(或重用,因为使用连接池)时,将使用以下命令:
exec sp_executesql N'
DELETE FROM dbo.ConnectionContextInfo WHERE SPID = @@SPID AND AttributeName = @UsernameAttribute;
INSERT INTO dbo.ConnectionContextInfo (SPID, AttributeName, AttributeValue) VALUES (@@SPID, @UsernameAttribute, @Username);
',N'@UsernameAttribute nvarchar(8),@Username nvarchar(16)',@UsernameAttribute=N'Username',@Username=N'domain\username'
go …Run Code Online (Sandbox Code Playgroud) 我正在使用BrentOzar的SQL Server First Responder Kit,因为我属于“管理 Microsoft SQL Server 的开发人员。如果它们出现故障或缓慢是您的错”。
运行的警告之一sp_blitz如下:
[DB] 数据库文件 DB_log 的最大文件大小设置为 10240MB。如果空间不足,即使可能有可用的驱动器空间,数据库也会停止工作。
日志文件位于与操作系统不同的驱动器上,我确实限制了它们的增长。所有数据库都有简单的恢复模式(大部分数据是通过复制和ETL自动获取的,从上次备份中恢复对我来说就足够了)。
该数据库有大约 20GB 的数据。
问题:如果恢复模式不强制我备份日志,数据库如何停止工作?
在像某些情况下这一个,SQL Server将默默地截断(N)VARCHAR值,导致严重的数据丢失时,错误地声明变量。
问题:可以将 SQL Server 配置为不以静默方式截断 VARCHAR 值吗?(并发出错误/引发异常)
我们的一位 DBA 向我们的团队抱怨说,他注意到大约有十几个睡眠连接实际上是永久性的。它们中的每一个都表示一个非常短的查询(单个记录中的单个记录通过其集群 PK 过滤返回)。
我的假设是,原因是 ADO.NET 连接池的使用以及经常进行相同查询的应用程序。
我试图找出这些睡眠连接是否会对 SQL Server 性能产生有意义的影响。默认情况下,ADO.NET 连接池的连接数限制为 100 个,因此我的假设是十几个休眠连接应该可以忽略不计。
我只能在这个线程中找到信息:
每次睡眠的最低成本约为 32kb RAM - 非常非常适中!
CPU 开销可能会产生一些微小的额外成本,但即使对于 10,000 个会话,也几乎无法检测到。
在会话/连接开销方面,SQL Server 表现得非常好!
这些信息准确吗?
我有一个在 SQL Server 2017 Express 上运行的测试环境,它只使用最近的数据(一个作业每月一次删除超过三个月的数据)。
该作业执行以下操作:
这篇文章描述了由于索引碎片而缩小数据库是多么糟糕,以及为什么重新索引也需要额外的空间。
上次运行从 9GB 数据库开始。删除需要 3-4 分钟,重新索引大约需要 30 秒。数据库减少到大约 5GB。
由于这是一个测试环境,我可以承受这种停机时间而不会出现任何问题。
问题:在删除了很大一部分数据后收缩 + 重新索引是不是很糟糕?
sql-server ×10
connections ×2
identity ×2
bulk-insert ×1
index ×1
performance ×1
select ×1
shrink ×1
sp-blitz ×1
string ×1
transaction ×1