【发布时间】:2020-10-07 07:13:01
【问题描述】:
我有一张包含数百万行的表格:
CREATE TABLE [dbo].[RequestIdentities]
(
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[UniqueKey] [nvarchar](256) NULL,
[Timestamp] [datetime] NULL,
CONSTRAINT [PK_RequestIdentities]
PRIMARY KEY CLUSTERED ([Id] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[RequestIdentities]
ADD CONSTRAINT [DF_RequestIdentities_Timestamp]
DEFAULT (GETDATE()) FOR [Timestamp]
GO
Web API 使用 ADO.NET 操作数据库并执行以下操作:
-
执行这个查询:
SELECT 1 FROM RequestIdentities WITH (nolock) WHERE UniqueKey = @key -
如果存在:
if(reader.HasRows) -
返回一个 http 响应。
-
否则,它会将 id 插入到表中:
INSERT INTO RequestIdentities(UniqueKey) VALUES(@key)
每分钟有数百个插入/更新,我可以做些什么来优化表,例如自定义统计信息/索引?
【问题讨论】:
-
那是小数据和低流量。 all 表需要索引。
TOP 1作为唯一键保证单个结果是没有意义的。充其量是无操作,最坏的情况是它会强制执行额外操作。WITH (NOLOCK)实际上是一个可怕的想法,导致结果脏或重复以及 more 锁。您没有提供有关此表的任何信息,除了它有一个 ID,因此无法说出可能需要优化的内容(如果有的话) -
您遇到过实际问题吗?顺便说一句,如果您只想检索单个值,请使用
ExecuteScalar而不是ExecuteReader。如果您想避免问题,请避免使用长期连接和事务。连接和事务累积锁,导致阻塞和延迟。这就是为什么创建和使用连接的常用方法是在using块内。 -
顺便说一句为什么
SELECT 1?如果您稍后需要读取该行的任何数据,则必须执行另一个查询。这是延迟的两倍,如果您使用事务,则使用更长时间的锁。如果要插入不存在的内容,可以使用INSERT ... WHERE NOT EXISTS()或MERGE在单个查询中执行操作。 -
BTW
UniqueKey需要唯一索引或约束,否则不能唯一 -
如果您的流量非常高且内存足够,您可以使用内存表来减少延迟和锁定。在这种情况下,将表视为持久的 Redis 缓存,只会更好。
标签: sql sql-server ado.net database-optimization