c# - SQL Server 请求在本地数据库中插入 200 行需要 20 秒并且还在增长
问题描述
我正在开发一个连接到本地 SQL Server 数据库的控制台应用程序(C#、asp-core 2.1、Entity Framework Core),这是(localdb)\MSSQLLocalDB
Visual Studio 提供的默认值(SQL Server 2016 v13.0)。
我面临的问题是将数据插入表中需要很长时间。该表有 400.000 行,6 列,我一次插入 200 个。
现在,请求需要 20 秒才能执行。而且这个执行时间不断增加。考虑到我仍然有 20.000 x200 行要插入的事实,值得弄清楚这个问题来自哪里!
几个事实:
- 表上没有索引
- 我的电脑不是新的,但我有一个相当不错的硬件(i7、16 Go RAM)而且我在插入时没有达到 100% CPU
所以,我的问题是:
- 40 万行是否被视为“大型”数据库?我以前从未使用过这么大的表,但我认为拥有这样的数据集很常见。
- 如何调查插入时间从何而来?到目前为止,我只安装了 Visual Studio(但我对其他选项持开放态度)
以下是相关表的 SQL 代码:
CREATE TABLE [dbo].[KfStatDatas]
(
[Id] INT IDENTITY (1, 1) NOT NULL,
[DistrictId] INT NOT NULL,
[StatId] INT NOT NULL,
[DataSourceId] INT NOT NULL,
[Value] NVARCHAR(300) NULL,
[SnapshotDate] DATETIME2(7) NOT NULL
);
编辑 我运行 SQL Server Management Studio,我发现请求减慢了整个过程。这是插入请求。
但是,通过查看实体框架创建的 SQL 请求,它看起来像是在进行内部连接并遍历整个表,这可以解释为什么处理时间会随着表的增加而增加。
我可能会漏掉一点,但你为什么需要枚举整个表来添加行?
正在执行的原始请求:
SELECT [t].[Id]
FROM [KfStatDatas] t
INNER JOIN @inserted0 i ON ([t].[Id] = [i].[Id])
ORDER BY [i].[_Position]
编辑和解决方案
我最终发现了这个问题,这是一个愚蠢的错误:我的Id
字段没有被声明为主键!所以系统必须为每个插入的行遍历整个数据库。我添加了 PK,现在 200 行需要 100 毫秒,并且这个持续时间是稳定的。
谢谢你的时间!
解决方案
我认为您可能只是缺少主键。您已向 EF 声明 Id 是实体键,但您在表上没有唯一索引来强制执行此操作。
而当 EF 想要获取插入的 ID 时,没有索引,它的成本很高。所以这个查询
SELECT t.id from KfStatDatas t
inner join @inserted0 i
on t.id = i.id
order by i._Position
执行 38K 逻辑读取,平均耗时 16 秒。
所以试试:
ALTER TABLE [dbo].[KfStatDatas]
ADD CONSTRAINT PK_KfStatDatas
PRIMARY KEY (id)
顺便说一句,您确定这是 EF6 吗?这看起来更像是 EF Core 批量插入。
推荐阅读
- carousel - AEM 6.3 上轮播的个性化
- javascript - 我有一个包含 n 个邮件 ID 的数组。我想按照它的域名排序
- sql - 使用 > 比较列时出错
- angular - Angular CLI 在构建之前修改 TS 文件?
- php - 我想在登录后将用户重定向到个人资料页面
- android - onDestroy 方法未在 android o 版本中调用
- sql - 使用执行流程任务将变量值传递到 .bat 文件
- angular - 如何在代码库中找到父组件 - angular 5?
- azure - Azure AD 和 Azure B2C 中的用户和组织管理
- logout - 如何使用 Amazon Cognito 注销终端节点?