does an update statement in oracle hold a lock even if no rows were updated - oracle11g

If I run an update statement in oracle that says '0 rows updated' because it does not match the where clause and i do not commit, does it still hold the lock on any protion of the table? My guess is no, but i cannot prove it.

No row locks are held after an update that didn't update anything (after all, if there is no row, which one should be locked?)
Your transaction will still have some share locks (on the table) but those are only there to prevent other transactions from altering the table. It's basically the same kind of "lock" a select statement acquires on the table.
From the manual:
A row is locked only when modified by a writer.
And further down in the manual:
A row lock, also called a TX lock, is a lock on a single row of table. A transaction acquires a row lock for each row modified
So if no row is changed, there can't be a lock.

It does not hold any lock.
Simple test case
Open two oracle sessions (sqlplus or sqldeveloper or by any other means)
update table1 where clause (session 1)
update table1 where clause (session 2)
Commit from session1 (if there is a table lock then this should hang)
commit from session2 (if there is a table lock then this statement will cause deadlock)
Condition is same with row locking (both sessions deleting same row if exists) as well.

As documented:
The locking characteristics of INSERT, UPDATE, DELETE, and SELECT ... FOR UPDATE statements are as follows:
The transaction that contains a DML statement acquires exclusive row locks on the rows modified by the statement. Other transactions cannot update or delete the locked rows until the locking transaction either commits or rolls back.
The transaction that contains a DML statement does not need to acquire row locks on any rows selected by a subquery or an implicit query, such as a query in a WHERE clause. A subquery or implicit query in a DML statement is guaranteed to be consistent as of the start of the query and does not see the effects of the DML statement it is part of.
A query in a transaction can see the changes made by previous DML statements in the same transaction, but cannot see the changes of other transactions begun after its own transaction.
In addition to the necessary exclusive row locks, a transaction that contains a DML statement acquires at least a row exclusive table lock on the table that contains the affected rows. If the containing transaction already holds a share, share row exclusive, or exclusive table lock for that table, the row exclusive table lock is not acquired. If the containing transaction already holds a row share table lock, Oracle Database automatically converts this lock to a row exclusive table lock.
The table lock is necessary to protect the table from changes while the update is in progress, and if no rows are modified by the update then this is the only lock applied.
If the statement carries out an update on a row that results in no change to that row (eg SET DATE_OF_BIRTH = NULL for a row where date_of_birth is already nullthe row lock is still taken.

Related

Can a optimistic lock give a deadlock?

Example:
i have a table A (id, version and a field) and a table B (id, version and a field).
i need to make a transaction that edit a record A, and then a record B.
begin transaction
update tableA set field='aaa', version=version+1 where id=1 and version=savedversion
-if recordupdated=0 then rollback
update tableB set field='bbb', version=version+1 where id=1 and version=savedversion
-if recordupdated=0 then rollback
commit
but if i have another thread that need to update the table in reverse order (in a complex environment, there is the possibility that a developer doesn't follow the policies), or needs to update table A (not same record as first transaction), then table B (same record as first transaction), then A (same record as first transaction), can occur a deadlock?
what is the right way to make a transaction in a optimistic lock?
could the solution be using only stored procedures?

Teradata - how to select without locking writers? (LOCKING ROW FOR ACCESS vs. LOCKING TABLE FOR ACCESS)

I am developing an application which fetches some data from a Teradata DWH. DWH developers told me to use LOCK ROW FOR ACCESS before all SELECT queries to avoid delaying writes to that table(s).
Being very familiar with MS SQL Servers's WITH(NOLOCK) hint, I see LOCK ROW FOR ACCESS as its equivalent. However, INSERT or UPDATE statements do not allow using LOCK ROW FOR ACCESS (it is not clear for me why this fails, since it should apply for table(s) the statement selects from, not to the one I insert into):
-- this works
LOCK ROW FOR ACCESS
SELECT Cols
FROM Table
-- this does not work
LOCK ROW FOR ACCESS
INSERT INTO SomeVolatile
SELECT Cols
FROM PersistentTable
I have seen that LOCKING TABLE ... FOR ACCESS can be used, but it is unclear if it fits my need (NOLOCK equivalent - do not block writes).
Question: What hint should I use to minimize writes delaying when selecting within an INSERT statement?
You can't use LOCK ROW FOR ACCESS on an INSERT-SELECT statement. The INSERT statement will put a WRITE lock on the table to which it's writing and a READ lock on the tables from which it's selecting.
If it's absolutely imperative that you get LOCK ROW FOR ACCESS on the INSERT-SELECT, then consider creating a view like:
CREATE VIEW tmpView_PersistentTable AS
LOCK ROW FOR ACCESS
SELECT Cols FROM PersistentTable;
And then perform your INSERT-SELECT from the view:
INSERT INTO SomeVolatile
SELECT Cols FROM tmpView_PersistentTable;
Not a direct answer, but it's always been my understanding that this is one of the reasons your users/applications/etc should access data through views. Views lock for access, which does not prevent inserts/updates. Selecting from a table uses read locks, which will prevent inserts/updates.
The downside is with access locks, the possibility for dirty reads exists.
Change your query as below and you should be good.
LOCKING TABLE PersistentTable FOR ACCESS
INSERT INTO SomeVolatile
SELECT Cols
FROM PersistentTable ;

How to upgrade SQLite deferred Transaction to RESERVED

I'm inserting data to a database where each "batch" must have a new unique id for the batch itself. I could add a batch table and use it's AUTOINCREMENT id, but I don't really need it for anything else, so it seems excessive.
I'm currently doing a SELECT MAX(batchid) + 1 FROM items and then using it for inserts, this is of course prone to race-conditions (2 new batches simultaneously can get conflicting ids)
Using an IMMEDIATE transaction is impractical. Is it possible to force an upgrade of a DEFERRED transaction to EXCLUSIVE before doing the select?
Some ideas;
Can I do some No-op cheap update?
Some explicit instruction to now go exclusive?
INSERT INTO items (batchid, value) VALUES ((SELECT MAX(batchid)+1 FROM items), "monkey"), ((SELECT MAX(batchid)+1 FROM items), "banana"), the idea being that the select is now explicitly part of the update?
It would indeed be possible to put the batch ID lookup into a subquery, but that would be a lot of duplication.
The easiest way is to do something to write to the database, such as PRAGMA user_version = x.

sqlite: dropping a table in a transaction?

I have a simple, single table sqlite3 database file that has exactly one table. There are no keys, foreign or domestic. There are no triggers. I have the following workflow:
If the database file exixts open it.
Start exclusive transaction
Select all rows from the table in order.
Operate on each row.
Delete each operated-on row.
When done, count the number of remaining rows in the table, if 0 then DROP the table then unlink the database file
Commit or Rollback the transaction
The drop-table always fails with the message that the table is locked. I've seen a couple of other posts that suggest that there could be open statement handles or other cruft lying around. Since I am using "sqlite_exec()"s for all of this I do not have any open DB anything except the DB handle itself.
Is drop table not allowed in transactions?
When dropping a table, you get the "table is locked" message when there is still some active cursor on the table, i.e., when you did not finalize a statement (or did not close a query object in whatever language you're using).

Use of AMPs in create table command in Teradata

I am new to Teradata. Can anyone tell me How exactly the AMPs going to helpful in creation of any table in Teradata.
Lets have a scenario.
I have a Teradata database with 4 AMPs. I learned that AMPs will usefull when we inserting the data into a table. Depending on the indexes it will distribute the data with the help of respected AMPs. But while creating the table, the command needs to execute through AMPs only. So i want to know which AMP will be used at that time??
The actual creation of the table in the data dictionary is a RowHash level operation involving a single AMP to store the record in DBC.TVM. Based on the other actions listed in the EXPLAIN there may be other AMPs involved as well but there is not single All-AMP operation. (This doesn't take into consideration the loading of the data and its distribution across the AMPs.)
Sample EXPLAIN:
1) First, we lock FUBAR.ABC for exclusive use.
2) Next, we lock a distinct DBC."pseudo table" for write on a RowHash
for deadlock prevention, we lock a distinct DBC."pseudo table" for
write on a RowHash for deadlock prevention, we lock a distinct
DBC."pseudo table" for read on a RowHash for deadlock prevention,
and we lock a distinct DBC."pseudo table" for write on a RowHash
for deadlock prevention.
3) We lock DBC.DBase for read on a RowHash, we lock DBC.Indexes for
write on a RowHash, we lock DBC.TVFields for write on a RowHash,
we lock DBC.TVM for write on a RowHash, and we lock
DBC.AccessRights for write on a RowHash.
4) We execute the following steps in parallel.
1) We do a single-AMP ABORT test from DBC.DBase by way of the
unique primary index.
2) We do a single-AMP ABORT test from DBC.TVM by way of the
unique primary index.
3) We do an INSERT into DBC.Indexes (no lock required).
4) We do an INSERT into DBC.TVFields (no lock required).
5) We do an INSERT into DBC.TVM (no lock required).
6) We INSERT default rights to DBC.AccessRights for FUBAR.ABC.
5) We create the table header.
6) Finally, we send out an END TRANSACTION step to all AMPs involved
in processing the request.
-> No rows are returned to the user as the result of statement 1.

Resources