SELECT FOR UPDATE necessary in CTE for UPDATE?











up vote
1
down vote

favorite












In PostgreSQL 9.6, is the below FOR UPDATE clause in this CTE necessary?



CREATE OR REPLACE FUNCTION next_job()
RETURNS json
LANGUAGE 'sql'

AS $BODY$

WITH thejob AS (
SELECT jobs.*, company.*
FROM (
select * from jobs
WHERE NOT EXISTS (SELECT * from jobs AS j2 where jobs.platform = j2.platform and jobs.project = j2.project AND start > now() - interval '1 hour')
order by priority, account_priority, job_id
limit 1) jobs
LEFT OUTER JOIN company
ON jobs.company_id = company.id
, enabled
WHERE enabled.status IS TRUE
FOR UPDATE of jobs
)
UPDATE jobs
SET start = now()
FROM thejob
WHERE jobs.job_id = thejob.job_id
RETURNING json_build_object('job_id', jobs.job_id, 'platform', jobs.platform, 'project', jobs.project, 'firstSeen', thejob.first_seen);

$BODY$;


The intent of the locking is to ensure that a job is taken by only one worker at a time (which seems to work as expected), but I'm seeing occasional deadlocks when calling this function and wonder if my explicit locking is potentially causing problems.



The WHERE NOT EXISTS is to ensure the same project doesn't get started twice, unless it has timed out after 1 hour.










share|improve this question
























  • Is it necessary? Not if you remove the CTE and put all the conditions in the WHERE clause of the UPDATE statement.
    – eurotrash
    Nov 7 at 9:37










  • Update: I changed the CTE to be a subquery as suggested by @eurotrash and removed the FOR UPDATE as also suggested by Laurenz Albe and can now report that the result was not as expected. Multiple workers consumed/updated the same job (row) at a time.
    – rgareth
    Nov 8 at 6:44















up vote
1
down vote

favorite












In PostgreSQL 9.6, is the below FOR UPDATE clause in this CTE necessary?



CREATE OR REPLACE FUNCTION next_job()
RETURNS json
LANGUAGE 'sql'

AS $BODY$

WITH thejob AS (
SELECT jobs.*, company.*
FROM (
select * from jobs
WHERE NOT EXISTS (SELECT * from jobs AS j2 where jobs.platform = j2.platform and jobs.project = j2.project AND start > now() - interval '1 hour')
order by priority, account_priority, job_id
limit 1) jobs
LEFT OUTER JOIN company
ON jobs.company_id = company.id
, enabled
WHERE enabled.status IS TRUE
FOR UPDATE of jobs
)
UPDATE jobs
SET start = now()
FROM thejob
WHERE jobs.job_id = thejob.job_id
RETURNING json_build_object('job_id', jobs.job_id, 'platform', jobs.platform, 'project', jobs.project, 'firstSeen', thejob.first_seen);

$BODY$;


The intent of the locking is to ensure that a job is taken by only one worker at a time (which seems to work as expected), but I'm seeing occasional deadlocks when calling this function and wonder if my explicit locking is potentially causing problems.



The WHERE NOT EXISTS is to ensure the same project doesn't get started twice, unless it has timed out after 1 hour.










share|improve this question
























  • Is it necessary? Not if you remove the CTE and put all the conditions in the WHERE clause of the UPDATE statement.
    – eurotrash
    Nov 7 at 9:37










  • Update: I changed the CTE to be a subquery as suggested by @eurotrash and removed the FOR UPDATE as also suggested by Laurenz Albe and can now report that the result was not as expected. Multiple workers consumed/updated the same job (row) at a time.
    – rgareth
    Nov 8 at 6:44













up vote
1
down vote

favorite









up vote
1
down vote

favorite











In PostgreSQL 9.6, is the below FOR UPDATE clause in this CTE necessary?



CREATE OR REPLACE FUNCTION next_job()
RETURNS json
LANGUAGE 'sql'

AS $BODY$

WITH thejob AS (
SELECT jobs.*, company.*
FROM (
select * from jobs
WHERE NOT EXISTS (SELECT * from jobs AS j2 where jobs.platform = j2.platform and jobs.project = j2.project AND start > now() - interval '1 hour')
order by priority, account_priority, job_id
limit 1) jobs
LEFT OUTER JOIN company
ON jobs.company_id = company.id
, enabled
WHERE enabled.status IS TRUE
FOR UPDATE of jobs
)
UPDATE jobs
SET start = now()
FROM thejob
WHERE jobs.job_id = thejob.job_id
RETURNING json_build_object('job_id', jobs.job_id, 'platform', jobs.platform, 'project', jobs.project, 'firstSeen', thejob.first_seen);

$BODY$;


The intent of the locking is to ensure that a job is taken by only one worker at a time (which seems to work as expected), but I'm seeing occasional deadlocks when calling this function and wonder if my explicit locking is potentially causing problems.



The WHERE NOT EXISTS is to ensure the same project doesn't get started twice, unless it has timed out after 1 hour.










share|improve this question















In PostgreSQL 9.6, is the below FOR UPDATE clause in this CTE necessary?



CREATE OR REPLACE FUNCTION next_job()
RETURNS json
LANGUAGE 'sql'

AS $BODY$

WITH thejob AS (
SELECT jobs.*, company.*
FROM (
select * from jobs
WHERE NOT EXISTS (SELECT * from jobs AS j2 where jobs.platform = j2.platform and jobs.project = j2.project AND start > now() - interval '1 hour')
order by priority, account_priority, job_id
limit 1) jobs
LEFT OUTER JOIN company
ON jobs.company_id = company.id
, enabled
WHERE enabled.status IS TRUE
FOR UPDATE of jobs
)
UPDATE jobs
SET start = now()
FROM thejob
WHERE jobs.job_id = thejob.job_id
RETURNING json_build_object('job_id', jobs.job_id, 'platform', jobs.platform, 'project', jobs.project, 'firstSeen', thejob.first_seen);

$BODY$;


The intent of the locking is to ensure that a job is taken by only one worker at a time (which seems to work as expected), but I'm seeing occasional deadlocks when calling this function and wonder if my explicit locking is potentially causing problems.



The WHERE NOT EXISTS is to ensure the same project doesn't get started twice, unless it has timed out after 1 hour.







postgresql






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 7 at 10:40









Laurenz Albe

41.2k92746




41.2k92746










asked Nov 7 at 9:07









rgareth

1,19121125




1,19121125












  • Is it necessary? Not if you remove the CTE and put all the conditions in the WHERE clause of the UPDATE statement.
    – eurotrash
    Nov 7 at 9:37










  • Update: I changed the CTE to be a subquery as suggested by @eurotrash and removed the FOR UPDATE as also suggested by Laurenz Albe and can now report that the result was not as expected. Multiple workers consumed/updated the same job (row) at a time.
    – rgareth
    Nov 8 at 6:44


















  • Is it necessary? Not if you remove the CTE and put all the conditions in the WHERE clause of the UPDATE statement.
    – eurotrash
    Nov 7 at 9:37










  • Update: I changed the CTE to be a subquery as suggested by @eurotrash and removed the FOR UPDATE as also suggested by Laurenz Albe and can now report that the result was not as expected. Multiple workers consumed/updated the same job (row) at a time.
    – rgareth
    Nov 8 at 6:44
















Is it necessary? Not if you remove the CTE and put all the conditions in the WHERE clause of the UPDATE statement.
– eurotrash
Nov 7 at 9:37




Is it necessary? Not if you remove the CTE and put all the conditions in the WHERE clause of the UPDATE statement.
– eurotrash
Nov 7 at 9:37












Update: I changed the CTE to be a subquery as suggested by @eurotrash and removed the FOR UPDATE as also suggested by Laurenz Albe and can now report that the result was not as expected. Multiple workers consumed/updated the same job (row) at a time.
– rgareth
Nov 8 at 6:44




Update: I changed the CTE to be a subquery as suggested by @eurotrash and removed the FOR UPDATE as also suggested by Laurenz Albe and can now report that the result was not as expected. Multiple workers consumed/updated the same job (row) at a time.
– rgareth
Nov 8 at 6:44












1 Answer
1






active

oldest

votes

















up vote
0
down vote













Because there is only a single row involved, the CTE seems unnecessary. This would only make sense if you want to update several rows and lock them in a certain order to avoid deadlocks.



Since the query will lock only a single jobs row, it cannot deadlock with anything by itself.



There most be some other data modifying statements in the same transaction that together with the statement you show create a deadlock.



Remember that locks are held until the end of a transaction!






share|improve this answer





















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














     

    draft saved


    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53186332%2fselect-for-update-necessary-in-cte-for-update%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    0
    down vote













    Because there is only a single row involved, the CTE seems unnecessary. This would only make sense if you want to update several rows and lock them in a certain order to avoid deadlocks.



    Since the query will lock only a single jobs row, it cannot deadlock with anything by itself.



    There most be some other data modifying statements in the same transaction that together with the statement you show create a deadlock.



    Remember that locks are held until the end of a transaction!






    share|improve this answer

























      up vote
      0
      down vote













      Because there is only a single row involved, the CTE seems unnecessary. This would only make sense if you want to update several rows and lock them in a certain order to avoid deadlocks.



      Since the query will lock only a single jobs row, it cannot deadlock with anything by itself.



      There most be some other data modifying statements in the same transaction that together with the statement you show create a deadlock.



      Remember that locks are held until the end of a transaction!






      share|improve this answer























        up vote
        0
        down vote










        up vote
        0
        down vote









        Because there is only a single row involved, the CTE seems unnecessary. This would only make sense if you want to update several rows and lock them in a certain order to avoid deadlocks.



        Since the query will lock only a single jobs row, it cannot deadlock with anything by itself.



        There most be some other data modifying statements in the same transaction that together with the statement you show create a deadlock.



        Remember that locks are held until the end of a transaction!






        share|improve this answer












        Because there is only a single row involved, the CTE seems unnecessary. This would only make sense if you want to update several rows and lock them in a certain order to avoid deadlocks.



        Since the query will lock only a single jobs row, it cannot deadlock with anything by itself.



        There most be some other data modifying statements in the same transaction that together with the statement you show create a deadlock.



        Remember that locks are held until the end of a transaction!







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 7 at 10:39









        Laurenz Albe

        41.2k92746




        41.2k92746






























             

            draft saved


            draft discarded



















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53186332%2fselect-for-update-necessary-in-cte-for-update%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            這個網誌中的熱門文章

            Tangent Lines Diagram Along Smooth Curve

            Yusuf al-Mu'taman ibn Hud

            Zucchini