【标题描述】:在表中同时有自增主键和时间戳字段情况下,会出现ID大但是时间戳小的记录
【测试类型:SQL功能】
【测试版本:openGauss 5.0.0 build a07d57c3】
问题描述
【操作系统和硬件信息】(查询命令: cat /etc/system-release, uname -a):
cat /etc/system-release
openEuler release 22.03 (LTS-SP1)
uname -a
Linux xxxxxx 5.10.0-136.12.0.86.oe2203sp1.aarch64 #1 SMP Tue Dec 27 17:51:19 CST 2022 aarch64 aarch64 aarch64 GNU/Linux
【测试环境】(单机/1主x备x级联备):
1主1备
【被测功能】:
表自增主键和时间戳字段
【测试类型】:
【数据库版本】(查询命令: gaussdb -V):
gaussdb -V
gaussdb (openGauss 5.0.0 build a07d57c3) compiled at 2023-03-29 03:36:31 commit 0 last mr
【预置条件】:
【操作步骤】(请填写详细的操作步骤):
在表中同时有自增主键和时间戳字段情况下,会出现ID大但是时间戳小的记录
CREATE TABLE t3 (
id BIGSERIAL primary key,
created_time timestamp DEFAULT pg_systimestamp(),
email character varying(40) NOT NULL
);
CREATE SEQUENCE t3_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
MAXVALUE 9223372036854775807
CACHE 1;
INSERT INTO t3(email)
SELECT
'user_' || seq || '@' || (
CASE (RANDOM() * 2)::INT
WHEN 0 THEN 'gmail'
WHEN 1 THEN 'hotmail'
WHEN 2 THEN 'yahoo'
END
) || '.com' AS email
FROM GENERATE_SERIES(1, 1000000) seq;
select *
from t3 a, t3 b
where
a.id>=400000
and b.id>=400000
and a.id<500000
and b.id<500000
and a.created_time<b.created_time
and a.id>b.id;
【预期输出】:
无记录返回
【实际输出】:
448362 2023-12-19 21:48:22 user_438351@hotmail.com 448361 2023-12-19 21:48:29 user_1@hotmail.com
448363 2023-12-19 21:48:22 user_438352@yahoo.com 448361 2023-12-19 21:48:29 user_1@hotmail.com
448364 2023-12-19 21:48:22 user_438353@hotmail.com 448361 2023-12-19 21:48:29 user_1@hotmail.com
448365 2023-12-19 21:48:22 user_438354@gmail.com 448361 2023-12-19 21:48:29 user_1@hotmail.com
448366 2023-12-19 21:48:22 user_438355@hotmail.com 448361 2023-12-19 21:48:29 user_1@hotmail.com
448367 2023-12-19 21:48:22 user_438356@hotmail.com 448361 2023-12-19 21:48:29 user_1@hotmail.com
448368 2023-12-19 21:48:22 user_438357@hotmail.com 448361 2023-12-19 21:48:29 user_1@hotmail.com
448369 2023-12-19 21:48:22 user_438358@hotmail.com 448361 2023-12-19 21:48:29 user_1@hotmail.com
448370 2023-12-19 21:48:22 user_438359@hotmail.com 448361 2023-12-19 21:48:29 user_1@hotmail.com
【原因分析】:
【日志信息】(请附上日志文件、截图、coredump信息):
【测试代码】:
Hey @ogdba, Welcome to openGauss Community.
All of the projects in openGauss Community are maintained by @opengauss_bot.
That means the developers can comment below every pull request or issue to trigger Bot Commands.
Please follow instructions at Here to find the details.
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。
Hi @ogdba, please use the command /sig xxx to add a SIG label to this issue.
For example: /sig sqlengine or /sig storageengine or /sig om or /sig ai and so on.
You can find more SIG labels from Here.
If you have no idea about that, please contact with @xiangxinyong , @zhangxubo .
/sig sqlengine
目前认为这个问题是非问题 ,获取时间戳的函数和获取自增键值的函数是两个函数,这两个函数执行的流程并不满足并发的原子性,这就在多线程的情况下,并没有办法保证获取自增键和获取时间戳的先后顺序是一致的。
另外,插入的方法也不对,因为整个语句都在同一个事务当中,而pg_systimestamp()的返回值是根据事务中的一些信息计算决定的,其计算的时间戳依赖于为stmtSysGTMdeltaTimestamp和t_thrd.time_cxt.stmt_system_timestamp的变量,stmtSysGTMdeltaTimestamp变量仅在SetStmtSysGTMDeltaTimestamp函数中初始化,且仅在开启事务的时候被调用
而t_thrd.time_cxt.stmt_system_timestamp变量则在SetCurrentStmtTimestamp函数中被调用,通过GDB断点调试发现在一个事务开启的过程中,SetCurrentStmtTimestamp函数仅仅呗StartTransaction函数调用了一次,
所以可知在同一个事务中,pg_systimestamp()返回的时间戳不变,所以上述的使用必然会出现ID大时间戳小的情况,毕竟两边的时间戳本身有先后且大小一直没有变化,但是自增键是有两个线程进行竞争的。可以尝试使用下面的方法进行数据插入
drop table if exists t3;
CREATE TABLE t3 (
id BIGSERIAL primary key,
created_time timestamp DEFAULT pg_systimestamp(),
email character varying(40) NOT NULL
);
DO $$DECLARE i record;
BEGIN
FOR i IN 1..10000
LOOP
execute 'insert into t3(email) select ''test2@qq.com'';';
END LOOP;
END$$;
这样,插入数据的语句就会产生10000个事务,产生的时间戳自然就会有变化。
2024年1月3日发起未复现或者未响应公示, 2024年1月16日公示满关闭,后续有问题可再次提单。
登录 后才可以发表评论