MySQL locking problem - php

I have a simple setup of a set of writers and a set of readers working with a MySQL ISAM table. The writers are only inserting rows while the readers are only checking for new rows.
OK, so I know that I don't need a lock in this situation, since I'm not modifying existing rows. However my Writers are accessing one more table that does need a lock. I piece of information seems irrelevant except for the following limitation stated in the MySQL documentation:
A session that requires locks must
acquire all the locks that it needs in
a single LOCK TABLES statement. While
the locks thus obtained are held, the
session can access only the locked
tables. For example, in the following
sequence of statements, an error
occurs for the attempt to access t2
because it was not locked in the LOCK
TABLES statement:
So to access the table I want to insert rows into, I NEED to lock it, which is causing me performance problems. Any suggestions of how to get around this?

Typically you lock and unlock immediately around the queries which need locking. The documentation is simply stating that for any set of queries run while you have a lock, all tables involved must be locked. You can unlock as soon as you're done and touch any other tables.
Also consider that InnoDB supports row-level locking, which is often preferable to table-locking for performance since other queries on other rows will not be locked out for reading while you're also writing.

Related

LOCK TABLES can cause deadlocks in InnoDB?

From MySQL manual ( https://dev.mysql.com/doc/refman/8.0/en/innodb-deadlocks.html ):
To reduce the possibility of deadlocks, use transactions rather than LOCK TABLES statements
How deadlocks are possible by using LOCK TABLES in InnoDB?
For example, if I write
SET autocommit=0;
LOCK TABLES t1 WRITE, t2 WRITE, t3 WRITE, t4 WRITE;
... do something with tables t1-t4 here ...
COMMIT;
UNLOCK TABLES;
do I really have to check errors like 1213 every time I execute this script?
If you make sure to lock all the tables you will read or write in one LOCK TABLES statement, you should be able to avoid deadlocks.
The other good reason to avoid using LOCK TABLES if you can use transactions instead is to allow row-level locking. LOCK TABLES only locks at the table level, which means concurrent sessions can't touch any rows in the table, even if your session doesn't need to lock them.
This is a disadvantage for software that needs to allow multiple sessions to access tables concurrently. You're forcing table-level locking, which will put a constraint on your software's throughput, because all sessions that access tables will queue up against each other, and be forced to execute serially.
What do you mean by "use t2"? A READ lock? What if I'm using only WRITE locks like in my example.
I think he means if you read from table t2. Since you have that table locked for WRITE, that includes blocking any readers of that table as well. No other session can read or write the table until you UNLOCK.
I'm not concerned about performance. I have a situation where I want to make things as simple as possible and LOCK TABLES feels much more intuitive to me than using transactions with paranoid level error checking.
You will eventually find a case where you want your software to have good performance. You'll have to become more comfortable using transactions.

What makes SQL Server decide what lock level to use (row, page or table lock?)

SQL Server has many ways of locking resource. I am trying to understand what make SQL Server pick what level of locks it will choose. I want to know when will it use Page or table lock over row lock?
Problem
I have a PHP application that uses transaction with every http request to ensure all queries are executed before a commit. One issue that is puzzling me is when many (5+) people use the application the app seems to be hanging (spinning for a long periods of time)! Nothing I can think of will cause such a behaviors except for database locks! The scenario that I am thinking it happening is that SQL Server is choosing to pick Page or Table lock over rowlock for some reason. I am trying to ensure that SQL Server is doing a row lock not Page or table lock. I am using an ORM so I can't use ROWLOCK hint in my queries.
Is there a way for me to run queries explain plan to see what lock level will be used?
As you can see here there is no default granularity in lock modes.
In general the optimizer will choose the best course of action to handle this.
Could it be a case of livelock due to a long running transaction that leads to resource starvation?
You can also check here and here for information on lock escalation, but I'd suggest to not disable it for any table.

Partially lock a table for a specific attribute

We want to prevent some concurrency issues in a database (we use event sourcing and want to insert an event to the event log in case the event is a valid one).
The problem is that we need to check if a certain operation is allowed (requiring a SELECT query and some checks in php) and then run a INSERT query to actually perform the operation.
Now, we can simply LOCK the entire table, do our checks and if they succeed, then insert (and remove the lock).
The problem with this is that it locks the entire table, which is overkill (there will be lots of queries on this table). What I would like to do is to lock all queries that want to do this select-insert operation for a specific object_id, but allow queries for all other object_id's to continue as if there is no lock.
I searched a bit but couldn't find a lock attribute command. There seems to be a lock row command in innoDB, but it's not really what we want (I think I'm not 100% sure what it does).
We can of course try to manually handle the locks (check if there exists some column with object_id in some seperate lock table and wait untill there is none), but that feels a bit fishy and error prone.
So, here's the actual question: is it possible to lock a table for a specific value of a column (object_id)?
It would be awesome if the lock only held for the specific SELECT-INSERT queries, and not for standalone SELECT's, but that doesn't matter that much for now.
Consider manual arbitrary locks with GET_LOCK();
Choose a name specific to the rows you want locking. e.g. 'xxx_event_id_y'. Where 'xxx' is a string specific to the procedure and table and 'y' is the event id.
Call SELECT GET_LOCK('xxx_event_id_y',30) to lock the name 'xxx_event_id_y'.. it will return 1 and set the lock if the name becomes available, or return 0 if the lock is not available after 30 seconds (the second parameter is the timeout).
Use DO RELEASE_LOCK('xxx_event_id_y') when you are finished.
Be aware; You will have to use the same names in each transaction that you want to wait and calling GET_LOCK() again in a transaction will release the previously set lock.
GET_LOCK() docs
I actually use this method to lock our application cache too (even when it doesn't use the DB), so it has scope outside the database as well.
Migrate tables to innodb if not already done, and use transactions.

php mysql, queries get locked and never returned

My system creates a lot of transactions as it has many users and a lot of data which is checked on a daily basis and renewed.
Somehow at a certain moment (i am not sure if it is the backup which did it) there is a LOCKED on queries. And Somehow they are never returned. Is this the deadlock?
The database is not returning anything to the code either, so I can't check if it's locked or not. Also, this causes other queries to be stopped and pile up and my server runs out of connections...
any idea's on this?
It may be caused by several issues. Most popular is MyISAM table lock. Just run this quesry: SHOW STATUS LIKE 'Table%';. Post it here. If Table_locks_waited is big (e.g. more than 0.5% of Table_locks_immediate) and you are using MyISAM switch to InnoDB table engine.
If your database is not very big, changing engine is pretty fast and transparent.
Note, that all your locked queries are "write" queries. That's because MyISAM has long running selects that lock tables. Moreover, selects can cause some kind of deadlock. Quotation from docs:
MySQL grants table write locks as follows:
If there are no locks on the table, put a write lock on it.
Otherwise, put the lock request in the write lock queue.
MySQL grants table read locks as follows:
If there are no write locks on the table, put a read lock on it.
Otherwise, put the lock request in the read lock queue.
Don't forget to tune innodb_* params!
If you don't want to switch to InnoDB (why?!), you can tune concurrent_insert parameter (try "2") in your my.cnf.
Btw, I see a lot of sleeping connections. Do you have persistent connections? If "yes", do you close them properly?

MySQL locking question

I have something similar to an online chat client. When one user sends a message it will be stored in a MySQL database table with id=currentID+1. I have another client long polling and waiting for message 'id=currentID+1'.
After this exchange, that row is never used again.
Do I need a lock in this case? The thing I'm worried about is that the reading PHP side will be able to see the row and read its values before the writing PHP side finishes creating the row.
MySQL won't make the row available until it's done reading (it automatically acquires a table lock in the case of MyISAM, or a row lock in the case of INNODB. So no, you should be ok so long as you're only inserting the row (and not later calling updates on it, etc)...
Writes in MySQL are atomic. Other queries cannot "see" the row until it is completely written, assuming you're using a single INSERT statement to do this.
the new row will only be seen by the select query after its inserted.
inserts are atomic
and yes myisam imploys table level locking, while innodb imploys row level locking.
and set of statements in a transaction are considered atmoic, there effect is not visible to any read until the transaction is committed, u can do a select shared to see uncommitted data.

Categories