sql - Redshift - 并发写入 - 如果查询是动态创建的,则插入不起作用

标签 sql concurrency amazon-redshift

我有一个存储过程:

CREATE OR REPLACE PROCEDURE public.lock_users(j_id "varchar",order_id "varchar",order_detail_id "varchar",insert_qry varchar(65535),rec_per_order "varchar")
    LANGUAGE plpgsql
AS $$       
declare 
lc_stmt varchar(65535);
BEGIN 

    lc_stmt = 'INSERT INTO test.USER_LOCK 
            SELECT '''||$1||''', '''||$2||''', '''||$3||''', user_id,cast(TIMEOFDAY() as timestamp) FROM ('||insert_qry|| 'AND USER_ID NOT IN (SELECT USER_ID FROM test.USER_LOCK)) WHERE ORDER_CNT <='||rec_per_order||'))';

    EXECUTE ''||lc_stmt||'';
END
  $$
;

从上述过程中生成的一个示例查询是:

INSERT INTO test.USER_LOCK
SELECT '657d7563-6de4-4dc9-ac74-3c23adf7a4e9', 'DSS-12345', 'DSS-74523-4-7569',
USER_ID,cast(TIMEOFDAY() as timestamp) 
FROM (
SELECT USER_ID FROM (
SELECT * FROM (
SELECT XA.USER_ID, XA.EMAIL_ID,YA.COMPANY_NAME
rank() OVER (PARTITION BY XA.account_id ORDER BY XA.account_id) ORDER_CNT 
FROM test.contacts_20 XA 
LEFT JOIN test.accounts_20 YA
ON XA.ACCOUNT_ID = YA.ACCOUNT_ID  
AND XA.COUNTRY = YA.COUNTRY 
WHERE XA.IS_CONTACT_SUPPRESSED = 0  
AND UPPER(XA.TELE_SUPPRESSION_LOB) != UPPER('DSS') 
AND XA.TELE_SUPPRESSION_LOB != 'BOTH' 
AND XA.IS_TELE_VERIFIED = 1 
AND XA.IS_TELE_SUPPRESSED = 0 
AND UPPER(PHONE_LINE) = 'DIRECT' 
AND XA.COUNTRY IN (
SELECT INCLUSION_VALUE FROM user_inc_list
WHERE JOB_ID = '657d7563-6de4-4dc9-ac74-3c23adf7a4e9' 
AND UPPER(INCLUSION_TYPE) = 'COUNTRY') 
AND XA.COUNTRY NOT IN (
SELECT EXCLUSION_VALUE FROM user_exc_list 
WHERE JOB_ID = '657d7563-6de4-4dc9-ac74-3c23adf7a4e9' 
AND UPPER(EXCLUSION_TYPE) = 'COUNTRY') 
AND XA.USER_ID NOT IN (
SELECT USER_ID FROM test.user_lead_20
WHERE (CURRENT_DATE - creation_date::date) <= 60 AND UPPER(LOB) != 'DSS' AND AGENCY_ID != '1456') 
AND XA.USER_ID NOT IN (
SELECT USER_ID FROM test.user_lead_20 
WHERE (CURRENT_DATE - creation_date::date) <= 60 AND UPPER(LOB) != 'DSS' AND SPONSOR_ID != '8659') 
AND USER_ID NOT IN (
select USER_ID 
from user_e_history 
where sf_campaign_id = 'DSS-12345' AND (CURRENT_DATE - creation_date::date) >= 7 AND channel = 'TELE') 
AND USER_ID NOT IN (
select USER_ID from user_e_history 
where creation_date::date = CURRENT_DATE AND channel = 'TELE' ) 
AND USER_ID NOT IN (
select USER_ID from test.user_lead_20
where sf_campaign_id = 'DSS-12345' GROUP BY USER_ID,"DOMAIN" HAVING COUNT(*) >= 3 ) 
AND USER_ID NOT IN (
select USER_ID from test.user_lead_20 
where AGENCY_ID = 1456 and (CURRENT_DATE - creation_date::date) <= 180 ) 
AND XA.E_domain NOT LIKE '%.gov'
AND USER_ID NOT IN (
SELECT USER_ID FROM test.USER_LOCK)) WHERE ORDER_CNT <=20));

当我并行执行这个存储过程时,它给我这个错误:

SQL Error [500310] [XX000]: [Amazon](500310) Invalid operation: 1023
Details: 
 Serializable isolation violation on table - 132075, transactions forming the cycle are: 2040186, 2040187 (pid:14687);

当我更改我的存储过程而不是传递参数和创建固定插入查询时,它起作用了。

这是有效的存储过程:

CREATE OR REPLACE PROCEDURE public.new_procedure(type_value "varchar")
    LANGUAGE plpgsql
AS $$   
declare 
lc_stmt varchar;
BEGIN 
    lc_stmt = 'INSERT into temp_table 
    select ct_id,email_id,first_name,last_name from users where active_type = '''||$1||''' ';

    EXECUTE ''||lc_stmt||'';
END
 $$
;

我无法理解此问题的原因和解决方案。请帮忙。

最佳答案

动态过程中的插入查询查找不在 user_lock 表中的 user_id 并插入结果。两个动态版本的结果集中似乎有共同的user_id。

所以假设当你的第一个版本被执行时,它可能会添加一个 user_id 到 user_lock 表,同样的 user_id 也可能在结果集中被第二个版本插入到 user_lock 表中。

因此,根据哪个版本先运行,这两个版本的结果集将与串行执行的结果集不同,即它们不是“可序列化隔离的”。

并且您在测试示例中没有遇到错误,因为它是一种独立的插入(用户和 temp_table)。

尝试 LOCK可能会解决这个问题。

关于sql - Redshift - 并发写入 - 如果查询是动态创建的,则插入不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60510969/

相关文章:

mysql - LIKE 不起作用后不在

mysql - 如何编写查询来返回每日回访用户?

go - 为什么并行化会减慢我的程序速度?

sql - Redshift : add column if not exists

database - 如何将超过 25 个项目/行写入 DynamoDB 表?

SQL 执行搜索/替换搜索

javascript - 我如何在 SQLite 中进行高级查询以按标签搜索文件?

java - HttpServletRequest.getServerName() 在并发使用中偶尔返回 null?

java - 两个ExecutorServices可以共享一个线程池吗?

python - 在一个 AWS Redshift 实例下创建(虚拟)多个数据库