PostgreSQL 是否提供内置的乐观并发控制机制,例如 SQL Server 的读提交快照隔离?读者可以在不阻塞的情况下读取所有行,但如果在事务期间修改了行,则写入将阻塞并失败。
编辑:在 RCSI 下,写入实际上不会“阻塞并失败”,而只是阻塞。
据我了解 InnoDB 支持
行级锁定
锁定用于当多个作者试图更新相同的行时。一次只有一个作者可以更新一行,第一个更新行的人会锁定它,直到他们提交更改。其他作家必须等到第一个作家提交。但至少对于行级锁定,它们只有在更新同一行时才会发生争用。
读锁可用于防止其他用户读取正在更新的记录(或页面),以便其他用户不会对即将过时的信息采取行动。
多版本并发控制
作家不会阻止读者
读者不会屏蔽任何人,也不会被任何人屏蔽。
这两者是相反的。
我的问题是:锁定或 mvcc 何时发生?我需要在哪里指定数据库应该使用哪一个?
我有一个大约有 8.5m 行的表格。该表是 tokudb,它具有下面描述的索引。在尝试运行如下更新语句时,我遇到了令人沮丧的性能:
update retail.lw_item_discovery
set price = 'X',
prev_price = 'Y',
last_updated = '2016-04-13',
last_price_change = '2016-04-13'
where market = 'XX'
and sku = '123456'
Run Code Online (Sandbox Code Playgroud)
执行此更新需要 40 秒以上的时间。还有其他类似的更新经常发生,但是这台机器的 I/O 子系统并没有受到丝毫压力(RAID SSD),并且还有大量可用的 RAM。
EXPLAIN 产量:
update retail.lw_item_discovery
set price = 'X',
prev_price = 'Y',
last_updated = '2016-04-13',
last_price_change = '2016-04-13'
where market = 'XX'
and sku = '123456'
Run Code Online (Sandbox Code Playgroud)
基于此 - 它选择PRIMARY索引而不是其他索引之一,例如cl_unique_idx在前两个位置的 where 语句中具有两列的索引。所以我很难过为什么计划者选择了PRIMARY而不是导致性能如此糟糕。以下是索引列表:
+----+-------------+-------------------+------------+-------+------------------------------------------------------------+---------+---------+------+------+----------+------------------------------+
| id | select_type | table | partitions | …Run Code Online (Sandbox Code Playgroud) 我在 SSMS 中执行一条语句,例如:
select Ident
from PART_Stamm
where VerketteterArtikelID = 'D9FA5CEC-E3C5-11E6-B088-F079596E5F58'
Run Code Online (Sandbox Code Playgroud)
在那里我可以显示执行计划。这完美地工作。现在我还需要显示PART_Stamm在执行上述查询期间在表上获取的锁数。我怎样才能得到这些信息?
我想阻止用户更改 MS SQL Server 数据库中的某些列。我无法将该列锁定为 READ ONLY,因为对该列进行了更改。让我尽可能解释清楚。我们的 ERP 允许我通过用户的安全选项卡阻止某些字段/列。听起来很棒。但是,如果一个人使用 ODBC 或 DSN 连接,他们将能够更改数据。例如,我不希望用户能够更改客户订单表中的成本或任何财务内容,但对他更正不正确的地址或运输信息没有任何问题。如果我将表锁定为只读,那么使用 ERP 也会阻止该列。我希望我在这里说得通。谢谢!
*编辑:结果证明这里的答案中没有任何解决方案,我在Python中使用SQLAlchemy,它是一个ORM。我在事务中执行下面的删除语句,但从未提交它。这导致发生大约 10 个打开的事务,最终所有事务都需要回滚,从而锁定整个表,直到回滚完成。
给定以下表结构,将使用最近日期时间的 update_time 连续插入记录。与数据库的单独连接会定期修剪日期超过 2 周的旧记录。
表结构:
以下插入运行非常频繁,具有不同的值:
重复以下删除语句直到需要为止,然后立即运行 select 以查看该过程是否完成
delete top(5000) from trade_options with (READPAST) where update_time < '<Two Weeks Ago>'
Run Code Online (Sandbox Code Playgroud)
活动监视器显示删除正在锁定,插入正在等待(LCK_M_IX):
谢谢
**编辑:这是作为脚本输出的索引/键
CREATE NONCLUSTERED INDEX [IX_order_option] ON [dbo].[order_option]
(
[update_time] DESC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
ALTER TABLE [dbo].[order_option] ADD PRIMARY KEY CLUSTERED
(
[exchange_id] ASC,
[symbol] ASC,
[update_time] ASC
)WITH (PAD_INDEX = OFF, …Run Code Online (Sandbox Code Playgroud) 最近,当我试图查找有关latch_ex 等待类型的信息时,我遇到了一个博客,如下所述,其中介绍了latch 和lock。
阅读此博客后,我只是对一件事感到好奇。当应用程序提交请求时,SQL Server 将首先在缓冲区缓存中查找信息,如果页面不在缓冲区缓存中,则仅从磁盘读取并将其放入缓冲区缓存中,然后再将信息发送给应用程序。我的问题基于上面的屏幕截图,其中指出闩锁和锁定需要避免两个线程更新同一页面。基本上所有来到SQL server的请求都会先进入buffer cache,如果buffer cache中的页面忙于更新,另一个线程将不得不等待。它不会回到磁盘,因为页面已经在内存中。那么锁定的目的是什么,因为每个请求都将通过内存完成并且有闩锁来保护页面
我花了两天的大部分时间试图弄清楚我的一张桌子中到底锁定了什么,以及为什么我会陷入从表面上看毫无意义的僵局。
我发现许多博客解释了如何使用未记录的 %%lockres%% 函数来获取表中特定行的哈希值。但是这些指南中的每一个都仅给出了有问题的锁位于表的主键上的示例。我有一个奇怪的情况,主键和唯一键都有锁。
对于上下文:我的主键是 UUID 字符串上的聚集索引。此表中唯一的其他索引是两列(不包括 pk)上的复合唯一键。当我对该表执行INSERT 操作时,我可以看到该表sys.dm_tran_locks上有两个XKEY 锁:一个用于 pk,另一个用于唯一约束。
我的死锁报告似乎暗示(除非我读错了——你可以在这里看到我的另一个问题)死锁是由第二个查询引起的,也锁定了唯一索引。
我一直在使用相同的模式在不同的数据库上进行试验,试图找出如何确定死锁的原因是否可以避免。我在一个打开的事务中做了一个 INSERT 并将资源描述与锁定表中所有记录的 %%lockres%% 进行比较,才发现主键上的锁映射到我添加的行,但是锁在唯一索引上根本不匹配表中的任何内容。
这里有人知道这个唯一索引的 %%lockres%% 是什么吗?它显然不是我表中的特定记录。
对于上下文,这是我运行以查看此信息的查询:
此查询列出了我当前数据库上的锁。下面输出。
SELECT dm_tran_locks.request_session_id,
dm_tran_locks.resource_database_id,
CASE
WHEN resource_type = 'object'
THEN OBJECT_NAME(dm_tran_locks.resource_associated_entity_id)
ELSE OBJECT_NAME(partitions.OBJECT_ID)
END AS ObjectName,
partitions.index_id,
indexes.name AS index_name,
dm_tran_locks.resource_type,
dm_tran_locks.resource_description,
dm_tran_locks.resource_associated_entity_id,
dm_tran_locks.request_mode,
dm_tran_locks.request_status,
cleanlockrs
FROM sys.dm_tran_locks
LEFT JOIN sys.partitions ON partitions.hobt_id = dm_tran_locks.resource_associated_entity_id
JOIN sys.indexes ON indexes.OBJECT_ID = partitions.OBJECT_ID AND indexes.index_id = partitions.index_id
CROSS APPLY(
SELECT LEFT(SUBSTRING(resource_description, …Run Code Online (Sandbox Code Playgroud) 我们很少有查询每 5 秒将它们的状态检查到一个表中并更新它们的状态。
下面是查询的样子(所有表列都在更新查询中)
update table1
set
Name='somename'
DetailMessage='Error'
LastUpdate=getdate()
where id=14
Run Code Online (Sandbox Code Playgroud)
最近这个表遇到了阻塞问题,上面的更新查询是主要的阻塞器。当我运行时Sp_Blitzindex,它显示没有丢失的索引,284 分钟的行锁争用..
以下是我到目前为止所做的几个步骤.. 1.
确保外键被索引(它们也是主键)
2.为可以从新索引中受益的选择语句创建索引,以便减少对该索引的锁争用
3.我还将 Fillfactor 减少到 10,以前每页用于存储 93 行,现在它每页只存储 7 行(仍然无法给自己一个 100% 的逻辑解释,说明此更改将如何帮助...)
任何进一步的建议..如果您需要任何进一步的细节,请告诉我
下面是表的架构(更改的列名),表只有 350 行,查询以每 5 秒 20/30 次查询的频率更新此表...
create table dbo.table1
(
[ID] [int] NOT NULL,
[Name] [varchar](500) NULL,
[DetailMessage] [nvarchar](max) NOT NULL ,
[LastUpdate] [datetime] NOT NULL
)
Run Code Online (Sandbox Code Playgroud)
PS:这是第三方查询,我们无法通过更改隔离级别等更改来修改源数据库...我只能添加索引
SQl 版本:SQl 2012
我可以在读取未提交模式下访问数据库,并且需要在操作环境中对表进行维护。我需要获取一个表的排他锁,做一个工作,然后释放锁。
在此维护期间,即使读取查询也不应将未提交的数据取回。
这个问题和答案看起来很有希望。我愿意:
begin transaction;
SELECT TOP (1) 1 FROM a WITH (TABLOCK);
Run Code Online (Sandbox Code Playgroud)
但是随后,SIX在 table 上获得了锁a。但是,这不会从选择查询中锁定表。如何获取Sch-M表上的锁?我最多可以通过以下方式获得Sch-S锁定:
SELECT TOP (1) * FROM a WITH (TABLOCK);
Run Code Online (Sandbox Code Playgroud)
这仍然不会阻止表上的选择查询。
locking ×10
sql-server ×7
mysql ×2
blocking ×1
concurrency ×1
innodb ×1
latch ×1
mvcc ×1
postgresql ×1
tokudb ×1
update ×1