目标:
删除三个表中数十亿条旧记录(大约 600GB),停机时间为零。
方法论和背景:
我计划一次删除与 100 万个 MyID 关联的批量记录(即 MyID 介于 1 和 1000000 之间)。当删除运行时,其中两个表将非常热,但第三个表上的活动可以安全地暂停。在两个热表中,MyID是聚簇键。在第三个冷表中,我在 MyID 上有一个非聚集索引。
除了 DELETE 操作之外,热表中的其他活动将包括 INSERT,可能每秒几次。MyID 是一个 IDENTITY,新插入的记录不会在任何 DELETE 批次的范围内。
如果有助于了解潜在性能,则在由 MyID 聚集的表上对这些行的样本批次进行聚合的 SELECT 花费的时间不到 1 秒,而在非聚集的表上则花费大约 2 秒。我没有这个特定数据库的产品副本可供使用,所以我不能说删除需要多长时间,但是一旦我将其部署到 DEV,我就会有一个更好的想法。
旁注:为了解决日志大小问题,我将这些批次包装在事务中,并将 TLog 备份频率从 15 分钟提高到 5 分钟。我有 150GB 的可用日志空间。
问题
我在 MS 文档中读到:
默认情况下,DELETE 语句始终在其修改的表上获取排它 (X) 锁,并保持该锁直到事务完成。
我对使用锁定提示非常谨慎,但在这种情况下我可以安全地使用锁定提示来避免 TABLOCKX 吗?除了锁定提示之外还有其他方法可以避免 TABLOCKX 吗?
是否可以编写一个UPDATE查询,如果它尝试更改的记录被另一个进程锁定(而不是等待锁被释放),则该查询将简单地退出?
我有一个进程应该更新表中的记录,有时这些记录会被锁定。更新这些记录是可取的,但不是必需的。如果记录正在使用中,我宁愿我的流程忘记更新并继续处理更重要的事情。
我当前的方法是将命令超时设置为 1 秒,但即使这也比我想要等待的时间长 - 正常更新需要不到一毫秒,因此等待一秒是一个主要开销。
所以这是永远挂起的查询:
ALTER TABLE tasks
ADD COLUMN in_progress BOOLEAN NOT NULL DEFAULT FALSE;
Run Code Online (Sandbox Code Playgroud)
该表tasks少于 20,000 行,每 5 分钟左右查询一次。
我检查了pg_stat_activity大约 10 次,但从未显示任何锁定表的查询:
SELECT *
FROM pg_stat_activity
WHERE query LIKE '%tasks%';
--- No results
Run Code Online (Sandbox Code Playgroud)
我尝试了真空吸尘器,但没有帮助:
VACUUM (VERBOSE, ANALYZE) tasks;
Run Code Online (Sandbox Code Playgroud)
我还尝试添加没有约束和默认值的列,我希望在这样的表上几乎是即时的,但是当我停止查询时,查询已经运行了 1 分钟:
ALTER TABLE tasks
ADD COLUMN in_progress BOOLEAN;
Run Code Online (Sandbox Code Playgroud)
我在同一时间段内对另一个表(约 1000 行)运行了查询,结果是即时的。
任何想法?
PostgreSQL 11.13
通过 DBeaver 执行的查询(为了以防万一,我多次无效/重新连接)。
如果我将 jdbc 隔离级别设置为在 SQL Server 中读取未提交,SQL Server 会锁定任何表、页、行等吗?
谢谢。
我对乐观锁的理解是,它使用表中每条记录的时间戳来确定记录的“版本”,这样当记录被多个进程同时访问时,每个记录的版本都有一个引用.
然后,当执行更新时,更新时间戳。在提交更新之前,它会第二次读取记录上的时间戳。如果它拥有的时间戳(版本)不再是记录上的时间戳(因为它自第一次读取以来已被更新),则该过程必须重新读取整个记录并将更新应用于它的新版本。
因此,如果我所说的任何内容不正确,请首先为我澄清。但是,假设我在这里或多或少是正确的......
这实际上如何在 RDBMS 中体现出来?这是在应用程序逻辑(SQL 本身)中强制执行的第二次读取/验证还是 DBA 制定的调整参数/配置?
我想我想知道读取时间戳并在时间戳陈旧时执行第二次更新的逻辑来自哪里。所以我问:是应用程序开发人员强制执行乐观锁,还是由 DBA 强制执行?无论哪种方式,如何?提前致谢!
RCSI(读提交快照隔离)是更改 SQL Server 中(默认)读提交隔离级别行为的数据库设置。
据我了解,这是 MSDN 博客文章“并发系列:最小化更新程序之间的阻塞”中的 sripts 的上下文,它告诉我们:
“使用 RCSI 的第二个技巧也不起作用,并且更新被行上的 session-1 阻塞在 X 锁后面,(C1 = 1)。原因是以下 UPDATE 语句在比读取提交更高的隔离级别执行。
update basic_locking set c2 = 1000 where c1 = 2
这是显示阻塞的输出

解决方案:这里有两个选择来解决这个问题:”
“输出”如何说明隐式默认隔离级别(已提交读)的隐式提升?
如何在某些语句的上下文中检查真正的隔离级别“跳跃”?
什么时候期待它们,它们为什么会发生?
我正在使用一个称为updated_at缓存失效的时间戳列。此处提供有关此特定技术的更多信息。
查询都具有相同的格式
UPDATE "managers" SET "updated_at" = '2014-07-25 15:00:24.212512' WHERE "managers"."id" = 1
问题是此列上的活动过多,导致写入缓慢。我假设减速是由锁定机制引起的。列上没有索引。
我们一直试图通过将可能导致多次更新的操作批处理来缓解这种情况,这确实有所帮助,但整个系统仍然受到影响。
我们实际上正在考虑将其移至 redis 并使用 INCR。
表“public.managers”
专栏 | 类型 | 修饰符
-------------------------+------------------------ -----+-------------------------------------------- -----------------
身份证 | 整数 | 非空默认 nextval('leads_managers_id_seq'::regclass)
account_id | 整数 |
created_at | 没有时区的时间戳 |
更新时间 | 没有时区的时间戳 |
通知_收件人| 文字 | 默认 ''::character 变化
用户名 | 字符变化(255) |
索引:
“leads_managers_pkey”主键,btree (id)
"index_leads_managers_on_uuid" UNIQUE, btree (uuid)
"index_leads_managers_on_account_id" btree (account_id)
我刚刚遇到一个查询:
INSERT [TableName] SELECT * FROM [TableName]
Run Code Online (Sandbox Code Playgroud)
请注意,这是同一张表。这个查询导致我的一个测试数据库严重阻塞(我想删除它但不能,这让我调查了这个问题)。
锁类型为 LCK_M_X。我无法终止会话 - 我收到以下消息:
PID 56:事务回滚正在进行中。预计回滚完成:27%。估计剩余时间:5715216 秒。
我不想等待回滚完成估计 2 个月。数据库的事务隔离级别是READ COMMITED。
是否可以终止此会话?如果您在关键任务数据库之一中发现这样的查询,您应该如何行动?
我有一个项目,我试图在其中使用 PostgreSQLON CONFLICT DO UPDATE子句,但我遇到了大量死锁问题。
我的架构如下:
webarchive=# \d web_pages
Table "public.web_pages"
Column | Type | Modifiers
-------------------+-----------------------------+---------------------------------------------------------------------
id | integer | not null default nextval('web_pages_id_seq'::regclass)
state | dlstate_enum | not null
errno | integer |
url | text | not null
starturl | text | not null
netloc | text | not null
file | integer |
priority | integer | not null
distance | integer | not null
is_text | boolean |
limit_netloc | boolean |
title …Run Code Online (Sandbox Code Playgroud) 在尝试创建死锁时,我遇到了无法理解的锁定问题:我正在更新按timekey列分区的大表:

我正在尝试运行两个更新语句:
BEGIN TRAN
UPDATE [Transform].[AllCommunications_Arch]
SET Callid = 10300503454
WHERE Callid = 10348103154
AND TimeKey = 20161205
Run Code Online (Sandbox Code Playgroud)
和
BEGIN TRAN
UPDATE [Transform].[AllCommunications_Arch]
SET Callid = 1234576704
WHERE Callid = 4321276791
AND TimeKey = 20160720
Run Code Online (Sandbox Code Playgroud)
每个人都应该更新一行,每个人都在不同的分区上运行,但由于某种原因,一个语句仍然阻塞另一个。DB 具有默认隔离杆(已提交读)。

CREATE TABLE [Transform].[AllCommunications_Arch](
[SessionId] [varchar](100) NULL,
[TimeKey] [int] NULL,
[Callid] [bigint] NULL,
[MemberId] [int] NULL,
[Duration] [int] NULL,
[CalledAt] [datetime] NULL,
[EndTime] [datetime] NULL....
) ON [Transform_Timekey_Daily_Arch_PS]([TimeKey])
WITH
(
DATA_COMPRESSION = PAGE
)
GO
CREATE CLUSTERED INDEX [CL_Transform_AllCommunications_Arch] ON [Transform].[AllCommunications_Arch] …Run Code Online (Sandbox Code Playgroud) locking ×10
sql-server ×5
postgresql ×3
update ×3
concurrency ×2
alter-table ×1
deadlock ×1
delete ×1
rdbms ×1
transaction ×1