在频繁更新的表上频繁查询的视图的锁定逻辑 - 请指教?
locking logic for frequently queried view on frequently updated tables - please advise?
我们面临以下情况(Teradata):
业务层在Table X_Past UNION ALL Table X_Today.
上频繁执行long-运行查询
Table X_Today 经常更新,比如说每 10 分钟一次。 X_Past 仅在午夜后一次(每次满载)。
- 写入进程不应阻塞读取进程。
- 写入应该在新数据可用时立即进行。
建议的方法:
2 "Today" 和一个 "past" table,加上一个 UNION ALL 视图,select 来自其中一个基于加载状态 table 中的值。
X_Today_1
X_Today_0
X_Past
loading process with load in X_Today_1 并将加载状态 table 中的 active_table 值设置为 "X_Today_1"
下次它将加载 X_Today_0 并将 active_table 值设置为 "X_Today_0"
等等
select 在 table 上使用的视图将按如下方式构建:
select *
from X_PAST
UNION ALL
select td1.*
from X_Today_1 td1
, ( select active_table from LOAD_STATUS ) active_tab1
where active_tab1.te_active_table = 'X_Today_1'
UNION ALL
select td0.*
from X_Today_0 td0
, ( select active_table from STATUS_LOG ) active_tab0
where active_tab1.te_active_table = 'X_Today_0'
我的主要问题:
执行select时,是否会锁定所有tables,还是仅锁定实际访问数据的那些?由于 where 子句,来自 Today_1/0 table 之一的数据将始终被忽略,并且此 table 应该可用于加载;
我们是否需要任何形式的锁定,或者是我们想要的(我怀疑是)默认锁定机制?
- 这行得通吗,还是我忽略了什么?
重要的是 loading 进程将等待以防 reading 进程花费超过 20 分钟并且加载程序即将再次刷新第二个 table。 阅读进程永远不应该真正被阻塞,除非它自己被阻塞。
非常感谢任何意见...
感谢您的帮助。
对您的问题的几点评论:
根据查询结构,优化器将尝试获取不同级别的默认锁(在本例中为 READ
锁)——很可能是 table 或行哈希锁。例如,如果您执行 SELECT * FROM my_table WHERE PI_column = 'value'
,您应该获得行哈希锁而不是 table 锁。
尝试 运行在您的 SELECT
上安装一个 EXPLAIN
,看看它是否给您任何锁定信息。优化器可能足够聪明,可以确定其中一个连接的 table 中有 0 行并减少锁定请求。如果它仍然锁定两个 table,请参阅此 post 的结尾以获取替代方法。
按原样编写的查询将导致 READ
锁,这将阻止 table 上的任何 WRITE
请求。如果您担心锁定问题/并发性,您是否考虑过使用显式 ACCESS
锁?这将使您的 SELECT
到 运行 无需等待您的写入查询完成。这称为“脏读”,因为在读取 table 时可能还有其他请求仍在修改它们,因此根据您的要求,它可能合适也可能不合适。
你的方法好像可行。您也可以做类似的事情,但不是有两个 UNIONs
,而是有一个指向“活动”table 的“X_Today”视图。加载过程完成后,您可以根据需要通过 MACRO
调用将视图重新指向适当的 table:
-- macros (switch between active / loading)
REPLACE MACRO switch_to_today_table_0 AS
REPLACE VIEW X_Today AS SELECT * FROM X_Today_0;
REPLACE MACRO switch_to_today_table_1 AS
REPLACE VIEW X_Today AS SELECT * FROM X_Today_1;
-- SELECT query
SELECT * FROM X_PAST UNION ALL SELECT * FROM X_Today;
-- Write request
MERGE INTO x_today_0...;
-- Switch active "today" table to must recently loaded one
EXEC switch_to_today_table_0;
您必须管理要写入哪个 table(或者也可能使用视图来完成)以及在您的应用程序中调用哪个“切换”宏。
需要考虑的一件事是,有两个逻辑上表示相同 table 的物理 table(即应该具有相同的数据)可能会允许其中一个 table缺少数据,需要手动同步。
此外,如果您还没有看过它们,还有一些想法可以将您的 SELECT
查询优化到 运行 更快:行分区、索引、压缩、统计、主索引选择。
我们面临以下情况(Teradata): 业务层在Table X_Past UNION ALL Table X_Today.
上频繁执行long-运行查询Table X_Today 经常更新,比如说每 10 分钟一次。 X_Past 仅在午夜后一次(每次满载)。
- 写入进程不应阻塞读取进程。
- 写入应该在新数据可用时立即进行。
建议的方法: 2 "Today" 和一个 "past" table,加上一个 UNION ALL 视图,select 来自其中一个基于加载状态 table 中的值。
X_Today_1
X_Today_0
X_Past
loading process with load in X_Today_1 并将加载状态 table 中的 active_table 值设置为 "X_Today_1"
下次它将加载 X_Today_0 并将 active_table 值设置为 "X_Today_0"
等等
select 在 table 上使用的视图将按如下方式构建:
select *
from X_PAST
UNION ALL
select td1.*
from X_Today_1 td1
, ( select active_table from LOAD_STATUS ) active_tab1
where active_tab1.te_active_table = 'X_Today_1'
UNION ALL
select td0.*
from X_Today_0 td0
, ( select active_table from STATUS_LOG ) active_tab0
where active_tab1.te_active_table = 'X_Today_0'
我的主要问题:
执行select时,是否会锁定所有tables,还是仅锁定实际访问数据的那些?由于 where 子句,来自 Today_1/0 table 之一的数据将始终被忽略,并且此 table 应该可用于加载;
我们是否需要任何形式的锁定,或者是我们想要的(我怀疑是)默认锁定机制?
- 这行得通吗,还是我忽略了什么?
重要的是 loading 进程将等待以防 reading 进程花费超过 20 分钟并且加载程序即将再次刷新第二个 table。 阅读进程永远不应该真正被阻塞,除非它自己被阻塞。
非常感谢任何意见...
感谢您的帮助。
对您的问题的几点评论:
根据查询结构,优化器将尝试获取不同级别的默认锁(在本例中为
READ
锁)——很可能是 table 或行哈希锁。例如,如果您执行SELECT * FROM my_table WHERE PI_column = 'value'
,您应该获得行哈希锁而不是 table 锁。尝试 运行在您的
SELECT
上安装一个EXPLAIN
,看看它是否给您任何锁定信息。优化器可能足够聪明,可以确定其中一个连接的 table 中有 0 行并减少锁定请求。如果它仍然锁定两个 table,请参阅此 post 的结尾以获取替代方法。按原样编写的查询将导致
READ
锁,这将阻止 table 上的任何WRITE
请求。如果您担心锁定问题/并发性,您是否考虑过使用显式ACCESS
锁?这将使您的SELECT
到 运行 无需等待您的写入查询完成。这称为“脏读”,因为在读取 table 时可能还有其他请求仍在修改它们,因此根据您的要求,它可能合适也可能不合适。你的方法好像可行。您也可以做类似的事情,但不是有两个
UNIONs
,而是有一个指向“活动”table 的“X_Today”视图。加载过程完成后,您可以根据需要通过MACRO
调用将视图重新指向适当的 table:
-- macros (switch between active / loading)
REPLACE MACRO switch_to_today_table_0 AS
REPLACE VIEW X_Today AS SELECT * FROM X_Today_0;
REPLACE MACRO switch_to_today_table_1 AS
REPLACE VIEW X_Today AS SELECT * FROM X_Today_1;
-- SELECT query
SELECT * FROM X_PAST UNION ALL SELECT * FROM X_Today;
-- Write request
MERGE INTO x_today_0...;
-- Switch active "today" table to must recently loaded one
EXEC switch_to_today_table_0;
您必须管理要写入哪个 table(或者也可能使用视图来完成)以及在您的应用程序中调用哪个“切换”宏。
需要考虑的一件事是,有两个逻辑上表示相同 table 的物理 table(即应该具有相同的数据)可能会允许其中一个 table缺少数据,需要手动同步。
此外,如果您还没有看过它们,还有一些想法可以将您的 SELECT
查询优化到 运行 更快:行分区、索引、压缩、统计、主索引选择。