MySQL Specify innodb_lock_wait_timeout for a specific query - mysql

I'm using MySQL 5.6. I have a specific query in my application that I don't want to be subject to the global innodb_lock_wait_timeout setting. Is there any way that I can specify that this specific query should wait a different amount of time for a lock before timing out?

You can only set this variable on global or session level, so you cannot set it just for a single query. Obviously, you can create a separate connection, set this variable on session level, execute your query and then close the connection.
You can find how to set a system variable on session level in mysql documentation on set command:
SET variable_assignment [, variable_assignment] ...
variable_assignment:
user_var_name = expr
| [GLOBAL | SESSION] system_var_name = expr
| [##global. | ##session. | ##]system_var_name = expr

Related

MySQL too many prepared statements

Is there a way to see what the prepared statements are that are associated with this error:
(OperationalError) failed to prepare the MySQL query:
Can't create more than max_prepared_stmt_count statements (current value: 20000)
One of several processes might be responsible for this problem and I'm trying to figure out which one it could be the easiest way I can think of, which is to see the text of the prepared statements and track it back to the source.
Is there any way to see what these prepared statements are so I can find the guilty party?
To see how many prepared statements are currently open, you can run:
SHOW GLOBAL STATUS LIKE 'com_%prepare%';
Which gives you something like:
Variable_name | Value
-------------------+--------
Com_prepare_sql | 2
Com_stmt_prepare | 2
Com_stmt_reprepare | 0
Com_xa_prepare | 0
To read the actual statements, you will need to look in the general query log for a while, and then read from it.
I like using a table for the general log:
-- set up
TRUNCATE TABLE mysql.general_log;
SET GLOBAL log_output = 'TABLE';
SET GLOBAL general_log = 'ON';
-- wait for some time
SET GLOBAL general_log = 'OFF';
-- read results
SELECT * FROM mysql.general_log WHERE argument LIKE 'prepare%' OR argument LIKE 'execute%';
You can see statements being prepared and executed:
command_type | argument
-------------+--------------------------------------------------------
Query | prepare st from "select * from people where name = ?"
Query | execute st Using #name

Mysql slow performance of very simple SELECT stored procedures

I am calling a stored procedure from JAVA, and it runs very slowly (about 120ms), even if it doesn't do much. For example:
BEGIN
SELECT '1';
END
If I have the stored procedure do literally nothing, or if I run the select commands outside of a stored procedure (ie execute the select * from.. directly in code), then it runs quickly (3ms or so).
BEGIN
END
I have 50 other SELECT stored procedures, and they all run equally slowly. If I run any if these commands outside of stored procedures (ie execute the SELECT * FROM... statement from JAVA without stored procedures), then they run very quickly.
I did look around and found others with similar issues, but couldn't find an answer that works in my case. I confirmed that collation and character set are the same between the database, the table, and the stored procedure.
INSERTS seem to run quickly. It really seems isolated to SELECT commands.
Environment: FreeBSD 10.3, DB - MariaDB 10.0.21
EDIT: Running the stored procedures from mysql commandline executes very quickly (0.00 sec).
EDIT: I enabled the general log and have the following output:
184381 Connect qwkdb#localhost as anonymous on productdb
184381 Query /* mysql-connector-java-6.0.2 ( Revision: c6da0fe501ad43d4ed6483b60ea796dc9fbe2d7b ) */SELECT ##session.auto_increment_increment AS auto_increment_increment, ##character_set_client AS character_set_client
, ##character_set_connection AS character_set_connection, ##character_set_results AS character_set_results, ##character_set_server AS character_set_server, ##init_connect AS init_connect, ##interactive_timeout AS interactive_timeout, ##l
icense AS license, ##lower_case_table_names AS lower_case_table_names, ##max_allowed_packet AS max_allowed_packet, ##net_buffer_length AS net_buffer_length, ##net_write_timeout AS net_write_timeout, ##query_cache_size AS query_cache_size
, ##query_cache_type AS query_cache_type, ##sql_mode AS sql_mode, ##system_time_zone AS system_time_zone, ##time_zone AS time_zone, ##tx_isolation AS tx_isolation, ##wait_timeout AS wait_timeout
184381 Query SET NAMES latin1
184381 Query SET character_set_results = NULL
184381 Query SET autocommit=1
184381 Query SET sql_mode = 'NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES'
184381 Query SELECT name, type, comment FROM mysql.proc WHERE name like 'GetAttributeValue' and db <=> 'productdb' ORDER BY name, type
184381 Query SHOW CREATE PROCEDURE productdb.GetAttributeValue
184381 Query CALL GetAttributeValue('hi')

Show all current locks from get_lock

Is there any way to select / show all current locks that have been taken out using the GET_LOCK function?
Note that GET_LOCK locks are different from table locks, like those acquired with LOCK TABLES - readers who want to know how to see those locks should read Detecting locked tables (locked by LOCK TABLE)
From MySQL 5.7 onwards, this is possible, but requires first enabling the mdl instrument in the performance_schema.setup_instruments table. You can do this temporarily (until the server is next restarted) by running:
UPDATE performance_schema.setup_instruments
SET enabled = 'YES'
WHERE name = 'wait/lock/metadata/sql/mdl';
Or permanently, by adding the following incantation to the [mysqld] section of your my.cnf file (or whatever config files MySQL reads from on your installation):
[mysqld]
performance_schema_instrument = 'wait/lock/metadata/sql/mdl=ON'
(Naturally, MySQL will need to be restarted to make the config change take effect if you take the latter approach.)
Locks you take out after the mdl instrument has been enabled can be seen by running a SELECT against the performance_schema.metadata_locks table. As noted in the docs, GET_LOCK locks have an OBJECT_TYPE of 'USER LEVEL LOCK', so we can filter our query down to them with a WHERE clause:
mysql> SELECT GET_LOCK('foobarbaz', -1);
+---------------------------+
| GET_LOCK('foobarbaz', -1) |
+---------------------------+
| 1 |
+---------------------------+
1 row in set (0.00 sec)
mysql> SELECT * FROM performance_schema.metadata_locks
-> WHERE OBJECT_TYPE='USER LEVEL LOCK'
-> \G
*************************** 1. row ***************************
OBJECT_TYPE: USER LEVEL LOCK
OBJECT_SCHEMA: NULL
OBJECT_NAME: foobarbaz
OBJECT_INSTANCE_BEGIN: 139872119610944
LOCK_TYPE: EXCLUSIVE
LOCK_DURATION: EXPLICIT
LOCK_STATUS: GRANTED
SOURCE: item_func.cc:5482
OWNER_THREAD_ID: 35
OWNER_EVENT_ID: 3
1 row in set (0.00 sec)
mysql>
The meanings of the columns in this result are mostly adequately documented at https://dev.mysql.com/doc/refman/en/metadata-locks-table.html, but one point of confusion is worth noting: the OWNER_THREAD_ID column does not contain the connection ID (like would be shown in the PROCESSLIST or returned by CONNECTION_ID()) of the thread that holds the lock. Confusingly, the term "thread ID" is sometimes used as a synonym of "connection ID" in the MySQL documentation, but this is not one of those times. If you want to determine the connection ID of the connection that holds a lock (for instance, in order to kill that connection with KILL), you'll need to look up the PROCESSLIST_ID that corresponds to the THREAD_ID in the performance_schema.threads table. For instance, to kill the connection that was holding my lock above...
mysql> SELECT OWNER_THREAD_ID FROM performance_schema.metadata_locks
-> WHERE OBJECT_TYPE='USER LEVEL LOCK'
-> AND OBJECT_NAME='foobarbaz';
+-----------------+
| OWNER_THREAD_ID |
+-----------------+
| 35 |
+-----------------+
1 row in set (0.00 sec)
mysql> SELECT PROCESSLIST_ID FROM performance_schema.threads
-> WHERE THREAD_ID=35;
+----------------+
| PROCESSLIST_ID |
+----------------+
| 10 |
+----------------+
1 row in set (0.00 sec)
mysql> KILL 10;
Query OK, 0 rows affected (0.00 sec)
Starting with MySQL 5.7, the performance schema exposes all metadata locks, including locks related to the GET_LOCK() function.
See http://dev.mysql.com/doc/refman/5.7/en/metadata-locks-table.html
SHOW FULL PROCESSLIST;
You will see the locks in there
If you just want to determine whether a particular named lock is currently held, you can use IS_USED_LOCK:
SELECT IS_USED_LOCK('foobar');
If some connection holds the lock, that connection's ID will be returned; otherwise, the result is NULL.
Reference taken from this post:
You can also use this script to find lock in MySQL.
SELECT
pl.id
,pl.user
,pl.state
,it.trx_id
,it.trx_mysql_thread_id
,it.trx_query AS query
,it.trx_id AS blocking_trx_id
,it.trx_mysql_thread_id AS blocking_thread
,it.trx_query AS blocking_query
FROM information_schema.processlist AS pl
INNER JOIN information_schema.innodb_trx AS it
ON pl.id = it.trx_mysql_thread_id
INNER JOIN information_schema.innodb_lock_waits AS ilw
ON it.trx_id = ilw.requesting_trx_id
AND it.trx_id = ilw.blocking_trx_id
I found following way which can be used if you KNOW name of lock
select IS_USED_LOCK('lockname');
however i not found any info about how to list all names.
Another easy way is to use:
mysqladmin debug
This dumps a lot of information (including locks) to the error log.

MySQL change database with variable value

I am setting a variable, and then I want to use the USE command to change the database. Unfortunately USE doesn't evaluate the variable.
SET #con="testDB";
Query OK, 0 rows affected (0.00 sec)
select #con;
+--------+
| #con |
+--------+
| testDB |
+--------+
1 row in set (0.00 sec)
use #con;
ERROR 1049 (42000): Unknown database '#con'
So the value of the variable is not evaluated when I try to connect. Any ideas?
I have found my own solution, so I am going to answer my own question, in case anybody is interested.
#outis you are right, it's not possible to use a variable with the command USE.
However, due to the fact that I want to create a table in a database specified at runtime, my solution would be to use dynamic SQL:
set #schema="testDB";
set #front="CREATE TABLE IF NOT EXISTS ";
set #endpart=".`TEST1` (DIM_ID INT(16)) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_unicode_ci;";
set #stat=concat(#front,#schema,#endpart);
prepare command from #stat;
execute command;
So basically this solution builds up the statement, prepares it and executes it.
#schema parameter can even be past down to the script. This way I dynamically build the create statement.
I don't think it's possible to USE #var; in some way. But in some cases doing it the other way around might be an option.
USE testDB;
SET #schema = DATABASE();

SET user defined variable in mysql return null?

When I created a user defined variable using
SET #a =10;
also i checked
SET #a := 10;
the above query executed successfully. while accessing the variable it gives me NULL value instead of 10. I accessed the defined variables using this query
SELECT #a;
The only way this can happen (in a client session) - and the way it happens for me from time to time - is you get bit by a short timeout on the client connection. It goes like this:
mysql> set #a = 10;
mysql> [wait for N+1 minutes, where N is the client timeout]
mysql> select #a;
+------+
| NULL |
+------+
| NULL |
+------+
1 row in set (0.00 sec)
You have to initialize your variables and use them within a contiguous client session. When the session goes away, you lose all your variables.
The other explanation, as pointed out by others in the comments, is that the commands are hitting the server from different connections; your problem might not be a timeout, but that you are originating the "SET ..." and "SELECT ..." commands in different connections. User variables are not shared across different connections.