Search code examples
mysqlinnodb

Mysql - InnoDB - Possible Key NULL when using function in an Update Query


BACKGROUND

I am working with a high traffic application which seems is extremely slow when executing the following.

Below is a description of my problem:

I have the following function defined:

CREATE FUNCTION getTableXMax() RETURNS INT
BEGIN
DECLARE NUM INT DEFAULT 0;
SELECT COALESCE((SELECT MAX(ID) FROM TABLE_X),0) INTO NUM;
RETURN NUM;
END //

TABLE_X has more than 30 million entries.

PROBLEMATIC QUERY

mysql> UPDATE TABLE_X SET COST = 0 WHERE ID=49996728;
    -> //
Query OK, 1 rows affected (0.00 sec)
Rows matched: 1  Changed: 0  Warnings: 0
mysql> UPDATE TABLE_X SET COLUMN_X=0 WHERE ID=getTableXMax();
    -> //
Query OK, 1 rows affected (1 min 23.13 sec)
Rows matched: 1  Changed: 0  Warnings: 0

------- QUESTION -----------

As you can see above, the problem is that the query below takes more than a minute to execute when using the mysql function. I want to understand why this happens (although overall implementation might be bad).

------- DEBUG --------------

I run some EXPLAIN queries to check the possible_keys that mysql uses in order to perform the search. As you can see below the query that uses the function has a NULL value for possible_keys - thus I assume the why the problem exists is probably answered. The questions remaining is how to fix it, and what is the reason.

mysql> EXPLAIN UPDATE TRANSCRIPTIONS SET COST = 0 WHERE ID=12434;//
+----+-------------+----------------+-------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table          | type  | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+----------------+-------+---------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | TRANSCRIPTIONS | range | PRIMARY       | PRIMARY | 4       | const |    1 | Using where |
+----+-------------+----------------+-------+---------------+---------+---------+-------+------+-------------+
1 row in set (0.00 sec)
mysql> EXPLAIN UPDATE TRANSCRIPTIONS SET COST = 0 WHERE ID=getTableXMax();//
+----+-------------+----------------+-------+---------------+---------+---------+------+----------+-------------+
| id | select_type | table          | type  | possible_keys | key     | key_len | ref  | rows     | Extra       |
+----+-------------+----------------+-------+---------------+---------+---------+------+----------+-------------+
|  1 | SIMPLE      | TRANSCRIPTIONS | index | NULL          | PRIMARY | 4       | NULL | 38608423 | Using where |
+----+-------------+----------------+-------+---------------+---------+---------+------+----------+-------------+

MYSQL VERSION

+-------------------------+------------------------------+
| Variable_name           | Value                        |
+-------------------------+------------------------------+
| innodb_version          | 5.6.34                       |
| protocol_version        | 10                           |
| slave_type_conversions  |                              |
| version                 | 5.6.34                       |
| version_comment         | MySQL Community Server (GPL) |
| version_compile_machine | x86_64                       |
| version_compile_os      | Linux                        |
+-------------------------+------------------------------+

I hope my question was thorough enough.


Solution

  • I think that

    UPDATE TABLE_X 
    SET COLUMN_X=0
    ORDER BY ID DESC 
    LIMIT 1
    

    is enough. And the function is not needed at all.


    If you want to save the function and the logic then use

    UPDATE TABLE_X, 
           ( SELECT getTableXMax() criteria ) fn
    SET COLUMN_X=0 
    WHERE ID=criteria;
    

    But as the first step - try to define the function as DETERMINISTIC.