繁体   English   中英

删除表中的选定行(如何提高速度)

[英]delete selected rows in table ( How do i increase the speed )

我有一个存储缓存时间的表,目前有大约1米的行。 当我用新版本的缓存项更新表时,我需要删除旧的缓存项(约3k项)。 关键是这些物品立即被发现但我会优先考虑,因为当客户拿出缓存物品时,我希望他们能够获得最新版本。

但删除仍然“慢”,需要几秒钟让最终用户等待,有没有办法让这个更快? 我正在做一个简单的SQL

DELETE FROM cache where cache_event_id = X

我的问题变成:我可以让查询更快(我希望缓存表只会增大,所以这个问题会变得更糟)? 我应该让删除sql运行自己的线程,并与用户可能旧项目一段时间生活在一起吗?

Pr请求表的其余信息。

CREATE TABLE [dbo].[cache](
    [cache_id] [int] IDENTITY(1,1) NOT NULL,
    [cache_name] [nchar](128) NOT NULL,
    [cache_event_id] [int] NOT NULL,
    [cache_encounter_id] [int] NOT NULL,
    [cache_type_id] [tinyint] NOT NULL,
    [cache_creation_date] [datetime] NOT NULL,
    [cache_data] [varbinary](max) NOT NULL
) ON [PRIMARY]

所有索引都是由sql server profiler创建的,好像我需要手动删除旧索引Index 1:

CREATE NONCLUSTERED INDEX [_dta_index_cache_6_366624349__K2_K3_K5_K4_7] ON [dbo].    [cache] 
(
    [cache_name] ASC,
    [cache_event_id] ASC,
    [cache_type_id] ASC,
    [cache_encounter_id] ASC
)
INCLUDE ( [cache_data]) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

索引2://可能不会被使用

CREATE NONCLUSTERED INDEX [_dta_index_cache_6_366624349__K5_1_2_3_4_6_7] ON [dbo].[cache] 
(
    [cache_type_id] ASC
)
INCLUDE ( [cache_id],
[cache_name],
[cache_event_id],
[cache_encounter_id],
[cache_creation_date],
[cache_data]) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

索引3(我假设这个用户正在删除)

CREATE NONCLUSTERED INDEX [_dta_index_cache_6_366624349__K3] ON [dbo].[cache] 
(
    [cache_event_id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

数据通过BulkCopy类插入表中

数据被取出(这是最关键的部分)

SqlCommand cmd = new SqlCommand("GetPageCache", connection);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@event_id", EventID); // int 
cmd.Parameters.AddWithValue("@encounter_id", EncounterID); // int 
cmd.Parameters.AddWithValue("@type_id", (int)CacheType); //int 
cmd.Parameters.AddWithValue("@cachename", CacheName); // Required in some cases, but 90% this is just a fallback

好消息是:如果DELETE语句总是删除大约3000行,那么随着表变大,情况可能不会变得更糟。

表的结构可能会影响DELETE操作所需的时间以及由于锁定而直接影响用户的时间。

索引“帮助”使得很容易识别~3000个注定行的行定位符。 但是,这些行必须位于“整个”表中(并在表中的每个索引中),然后删除。 这种情况的一个可能原因是这些3000行在不同的数据页上分布在表(和索引)上。

对你来说没有一个通用的答案,但你应该好好看看你的表的组织和索引。 可能有一种方法可以更改组织和索引,使得注定的行将位于较少的数据页上,并且DELETE的查询计划将不会执行3000次单独的查找以达到它们。

如果您为[cache]发布CREATE TABLE和CREATE INDEX语句,我可能会有特定的建议而不是概括。

补充说明:

这是一些更多的想法。

你有PRIMARY KEY约束吗? 如果没有,则没有聚集索引,这意味着您的表存储为堆。 这并不好,特别是对于经历了大量活动的桌子。 虽然我没有详细说明,但我同意下面的Dems。 它应该有助于主键(应该是群集)(cache_event_id,cache_id)。

另一个瓶颈可能是缓存数据本身。 您已在三个索引中包含它,因此您将它存储在四个位置! 我只是猜测,但你似乎不太可能一次从多行返回cache_data列的查询。 因此,您只能将cache_data存储在聚簇索引中(默认情况下,聚簇索引包括所有列)。 数据库调优顾问很好地为您提供想法,但完全按照它所说的做并不总是一个好主意。

典型的cache_data列有多大? 如果它几乎总是很大(大小超过8K),它将导致LOB溢出页面的大量活动。 当有很多LOB活动时,我不是工作负载调优的专家,但是可能有一些很好的资源和建议。 要考虑的一件事(直到你尝试索引改进并实际查看内存使用,缓存命中等)是考虑允许更多表行适合页面的更改:

  1. 重新考虑是否需要cache_name类型为nchar(128)。 (你可能会考虑它。它总是接近128字节的数据吗?是否需要使用Unicode并且值得多留空间?如果没有,也许nvarchar(128)或varchar(128)都可以。)

  2. 考虑将'大值类型超出行'选项设置为ON可能有用。 默认值为OFF,这可能会导致每个数据页平均只有一个表行,但不会减少对LOB溢出页的需求。 查看sp_spaceused或sys.dm_db_partition_stats的结果以尝试评估此问题。 如果每页只有1行或2行,则可能有助于更改设置。

如果有很多删除,它可能会写很多东西到日志文件。 如果涉及任何关系,可能需要花费很长时间来确定是否允许删除记录。

我有一个类似的问题,(但在我的情况下,我需要确保旧记录不可见)并最终添加一个名为隐藏的位字段。 所以'delete'例程实际上只是一个更新语句,将hidden设置为true,并且修改了查找以忽略隐藏的记录。

然后我可以在不影响用户的情况下删除后台隐藏的记录。

让最终用户等待执行缓存清理的删除调用似乎是不必要的。 这应该是一个后台工作/线程。

或者,您可以使用memcached之类的东西来处理缓存读取和过期。

绝对应该异步地清理这些数据(通过预定的sql作业,服务,填充数据的作业等)。 如果您担心在有机会删除它们之前返回查询中的旧项目,则可以实现某种类型的版本控制方案,该方案仅返回最新项目。

我认为问题的一部分是设计,但假设我们只想加速删除而不改变其他内容?

只有“cache_event_id”的索引确实用于删除,但不是你可能会想到的方式。 使用执行计划运行删除,您将在使用索引后看到它然后也使用主键(假设已聚集)。 索引基本上只是用作查找需要删除的主键的捷径。 主键(或任何聚簇索引)允许RDBMS物理地知道记录的位置,因此可以删除它们。

此外,删除记录时,所有索引都需要更新。 根据您拥有的索引数量以及它们的设置方式,这可以是labourios。

所以我的两个推荐是:
1.确保主键或聚簇索引具有“cache_event_id”作为第一个字段
2.合理化索引的数量,如果可能,这可能涉及重写一些查询

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM