Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1oUH1P-0008IW-4n for pgsql-admin@arkaria.postgresql.org; Sat, 03 Sep 2022 00:28:27 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1oUH1L-0001sa-UC for pgsql-admin@arkaria.postgresql.org; Sat, 03 Sep 2022 00:28:23 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1oUH1L-0001sR-D7 for pgsql-admin@lists.postgresql.org; Sat, 03 Sep 2022 00:28:23 +0000 Received: from mail-ot1-x32f.google.com ([2607:f8b0:4864:20::32f]) by makus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1oUH1I-0008FU-OJ for pgsql-admin@lists.postgresql.org; Sat, 03 Sep 2022 00:28:22 +0000 Received: by mail-ot1-x32f.google.com with SMTP id br15-20020a056830390f00b0061c9d73b8bdso2533766otb.6 for ; Fri, 02 Sep 2022 17:28:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=in-reply-to:from:references:to:content-language:subject:user-agent :mime-version:date:message-id:from:to:cc:subject:date; bh=MUdg6vtn9HHA6kQIKkWquXaT3xsdXHwH3NOlKQF8At8=; b=lr/188Vb4kA/tChVRoJOzeK2CJGNCzh2nbgQ2oC6ij6MHIUSC97pnH+6u3DybfDh4Z ENJ7HrrWQXN2OYG9okpzevwcxLxjHzjT5H0nevDeoq9uFnsxMPUh9otIeiLdYULKz/9T 7nbTDICMV8he6XoqXenC5fWtk3q8d0e+dfvlTlWYublqU1wfGxIBbNMS3bOWhLXH73ai O1932sGDGgRdwFJMFfc4rWJI782Vh8so+DWrCpsWXs8Wqw+Dmh8ScNqadpr4HB4/H33I aI8ytI0MB9cVrZxFCNUbkJNIy5J3QrJujgxcPCScZEWC/OpMBkOAmfSkU70yrFtgMBlh NkZg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=in-reply-to:from:references:to:content-language:subject:user-agent :mime-version:date:message-id:x-gm-message-state:from:to:cc:subject :date; bh=MUdg6vtn9HHA6kQIKkWquXaT3xsdXHwH3NOlKQF8At8=; b=DFxtjFEtJleyy0qIpAcQRhz1fC+lAL71Fv+BbhQSNya02NteGTX3ykeT0qx58Rphc9 uLjJDajL71nThLF3GmFqEpP2PXZ9pLhLja/Mv529yFD7wLi9irWeGR9cGR8T8FCAOFw8 JYYlpSu5tPhT7wKuAgR18+gDekoul7FXtFxX8DIG3NXIHg4zZZjZa/TSoid3lwFpwapO EzJIXGY0EhCowcxJrNopZzyENK46OLIrwgJu7x4T8gSx5EDVSjQMkW98hh8kxKh477oM uzA+wWvw7S6b9tH7nPhwGV5o0hZ4/escw4d1Nr0HsCDuL0Tfb9xa7ip5p/X1H1WUdXoj 0BMw== X-Gm-Message-State: ACgBeo2l0k6/u0wCu6hpPhpAtJIMAvHEq1x4kkS6f5tuzDUVBpLBbF1t vqSX/leSubiaZmAkPKnMQ4IgnLJqWPM= X-Google-Smtp-Source: AA6agR5tp1aJEdNV4nRfBwBIb6arZCd2aDzvbprMqAWyUHEnG4icv3Azr9o1YLXoa5eQ7XcwTEop9g== X-Received: by 2002:a9d:4f11:0:b0:636:ef73:5e99 with SMTP id d17-20020a9d4f11000000b00636ef735e99mr15361298otl.277.1662164898906; Fri, 02 Sep 2022 17:28:18 -0700 (PDT) Received: from [192.168.88.10] (ip68-11-68-85.no.no.cox.net. [68.11.68.85]) by smtp.googlemail.com with ESMTPSA id cz20-20020a056870649400b0010c0d04eb00sm1929512oab.2.2022.09.02.17.28.18 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 02 Sep 2022 17:28:18 -0700 (PDT) Content-Type: multipart/alternative; boundary="------------5kfhIYrHIa6KfuZulqA4vEq4" Message-ID: Date: Fri, 2 Sep 2022 19:28:17 -0500 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.9.1 Subject: Re: Understanding updates and deadlocks more clearly Content-Language: en-US To: pgsql-admin@lists.postgresql.org References: From: Ron In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk This is a multi-part message in MIME format. --------------5kfhIYrHIa6KfuZulqA4vEq4 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit On 9/2/22 16:15, Wells Oliver wrote: > Hey folks: I want to clarify a few things about locks on updates: > > 1- can two processes update the same table if they are updating different > rows? You can test this yourself by trying it, > > 2- in the event of two processes trying to update the same row, does this > always result in a deadlock? If txn 1 starts, updates TABLE_A then TABLE_B and commits, while "at the same time" txn 2 (say it's the same code but a different end user processing different data) does the same thing to the same or similar rows, you *might* have a *lock conflict* (depending on RDBMS, transaction type, type of indices, length of transaction, how well it's written, etc). OTOH, you might get a *deadlock* if If txn 1 starts, updates TABLE_A then TABLE_B and commits, while "at the same time" txn 2 updates TABLE_*B* then TABLE_A. In that case, txn 1 locks a chunk of TABLE_A, while txn 2 locks a chunk of TABLE_*B*, and then txn 1 tries to lock TABLE_*B* but can't, because txn 2 has already locked it.  "Simultaneously", txn 2 tries to lock TABLE_*A* but can't, because txn 1 has already locked it. That's a simplistic form of deadlock, which for 25 years competent DBMSs have been able to avoid.  (Even so, you can sometimes force the issue by using SERIALIZABLE transaction mode.) > > 3- is there a way to create a system whereby potentially concurrent > processes can update the same row in a given table, can the server be made > to queue those updates, etc? This is what DBMSs have been doing for *50+ years*.  Of course a single CPU system can by definition only do one thing at a time; while multi-CPU systems can execute multiple CPU op-codes at once, at some point you'll get to a serialized bottleneck.  For example, the disk controller can only write *one "thing"* at at time to a disk block. Thus, at some deep stage, everything is serialized.  Having said that, there are many layers between your application sending SQL code to Postgresql, and there hints that you can provide the RDBMS, and also there are hints that the RDBMS can figure out itself. PostgreSQL uses MVCC (multi-version concurrency control, which keeps multiple versions of a record on disk; each transaction can only see one version, and at some point some of the record versions are marked "dead", and they just sit there wasting space and IO (since disks read blocks, not Postgresql records).  This is why VACUUM is so important in UPDATE/DELETE heavy tables. Transaction length also plays into concurrency (or lack thereof).  A txn that starts, does some quick DB changes (having done as much work as possible beforehand) and then commits allows for faster concurrency than one that starts, does some work, does a bunch of unrelated tasks, inefficiently modifies the database, and then commits. *Or worse*, starts a transaction, does some work, and then *waits to commit* until the user (who just went to lunch!!! presses a key. -- Angular momentum makes the world go 'round. --------------5kfhIYrHIa6KfuZulqA4vEq4 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: 8bit On 9/2/22 16:15, Wells Oliver wrote:
Hey folks: I want to clarify a few things about locks on updates:

1- can two processes update the same table if they are updating different rows?

You can test this yourself by trying it,


2- in the event of two processes trying to update the same row, does this always result in a deadlock?

If txn 1 starts, updates TABLE_A then TABLE_B and commits, while "at the same time" txn 2 (say it's the same code but a different end user processing different data) does the same thing to the same or similar rows, you might have a lock conflict (depending on RDBMS, transaction type, type of indices, length of transaction, how well it's written, etc).

OTOH, you might get a deadlock if If txn 1 starts, updates TABLE_A then TABLE_B and commits, while "at the same time" txn 2 updates TABLE_B then TABLE_A.

In that case, txn 1 locks a chunk of TABLE_A, while txn 2 locks a chunk of TABLE_B, and then txn 1 tries to lock TABLE_B but can't, because txn 2 has already locked it.  "Simultaneously", txn 2 tries to lock TABLE_A but can't, because txn 1 has already locked it.

That's a simplistic form of deadlock, which for 25 years competent DBMSs have been able to avoid.  (Even so, you can sometimes force the issue by using SERIALIZABLE transaction mode.)


3- is there a way to create a system whereby potentially concurrent processes can update the same row in a given table, can the server be made to queue those updates, etc?

This is what DBMSs have been doing for 50+ years.  Of course a single CPU system can by definition only do one thing at a time; while multi-CPU systems can execute multiple CPU op-codes at once, at some point you'll get to a serialized bottleneck.  For example, the disk controller can only write one "thing" at at time to a disk block.

Thus, at some deep stage, everything is serialized.  Having said that, there are many layers between your application sending SQL code to Postgresql, and there hints that you can provide the RDBMS, and also there are hints that the RDBMS can figure out itself.

PostgreSQL uses MVCC (multi-version concurrency control, which keeps multiple versions of a record on disk; each transaction can only see one version, and at some point some of the record versions are marked "dead", and they just sit there wasting space and IO (since disks read blocks, not Postgresql records).  This is why VACUUM is so important in UPDATE/DELETE heavy tables.

Transaction length also plays into concurrency (or lack thereof).  A txn that starts, does some quick DB changes (having done as much work as possible beforehand) and then commits allows for faster concurrency than one that starts, does some work, does a bunch of unrelated tasks, inefficiently modifies the database, and then commits.  Or worse, starts a transaction, does some work, and then waits to commit until the user (who just went to lunch!!! presses a key.

--
Angular momentum makes the world go 'round.
--------------5kfhIYrHIa6KfuZulqA4vEq4--