Bug #114092 WHERE statement on an indexed decimal column hangs
Submitted: 22 Feb 23:40 Modified: 24 Feb 13:55
Reporter: Daniel Bircher Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: Optimizer Severity:S5 (Performance)
Version:Ver 8.0.36-0 OS:Ubuntu (ubuntu 22.04.1)
Assigned to: CPU Architecture:x86 (Linux on x86_64 ((Ubuntu)))
Tags: decimal values, INDEX, MYISAM engine

[22 Feb 23:40] Daniel Bircher
Description:
Performing a WHERE filter on an indexed DECIMAL column hangs.  Please see steps below to repeat the issue.  I've tested on multiple servers directly through the CLI, as well as, through MySQL Workbench.  

Please let me know if I can provide any further details.  Thanks. 

How to repeat:
Please run the following:

DROP PROCEDURE `prepare_data`;
DELIMITER $$
CREATE DEFINER=`user`@`ip%` PROCEDURE `prepare_data`()
BEGIN
  DECLARE i INT DEFAULT 1;
  WHILE i < 1000000 DO
    INSERT INTO _TEST (dec_ , var1_) VALUES (ROUND(-1+2*RAND(),2), CONCAT(UUID(), UUID(), UUID(), UUID(), UUID()));
    SET i = i + 1;
  END WHILE;
END$$
DELIMITER ;

 -- Create test data
DROP TABLE IF EXISTS _TEST;
CREATE TABLE `_TEST` (
   `dec_` decimal(15,2) DEFAULT NULL,
   `var1_` varchar(250) DEFAULT NULL
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
CALL prepare_data();

 -- Run tests
SELECT * FROM _TEST WHERE dec_ < 0;  -- Works -- 3	31	16:25:54	SELECT * FROM _TEST WHERE dec_ < 0 LIMIT 0, 1000	1000 row(s) returned	0.016 sec / 0.000 sec
ALTER TABLE _TEST ADD INDEX dec_(dec_);
SELECT * FROM _TEST WHERE dec_ < 0; -- Does not work -- Ran for 30+ minutes.  Killed process.  Process hung and did not clear until service was restarted.
ALTER TABLE _TEST DROP INDEX dec_;
SELECT * FROM _TEST WHERE dec_ < 0; -- Works -- 3	36	16:28:29	SELECT * FROM _TEST WHERE dec_ < 0 LIMIT 0, 1000	1000 row(s) returned	0.000 sec / 0.000 sec
[22 Feb 23:50] Daniel Bircher
As a side note, var1_ generally represents a free-text field.  The values contained within does not appear to be relevant.
[23 Feb 8:22] MySQL Verification Team
Hello Daniel Bircher,

Thank you for the report and test case.
I quickly tried to reproduce locally with the provided test case but not seeing any issues. Could you please share exact conf file used? Thank you.

--
-- Env
    Platform | Linux
     Release | Red Hat Enterprise Linux Server release 7.9 (Maipo)
      Kernel | 5.4.17-2102.206.1.el7uek.x86_64
Architecture | CPU = 64-bit, OS = 64-bit
   Threading | NPTL 2.17
    Compiler | GNU CC version 4.8.5 20150623 (Red Hat 4.8.5-44.0.3).
     SELinux | Disabled
 Virtualized | VMWare
# Processor ##################################################
  Processors | physical = 1, cores = 8, virtual = 16, hyperthreading = yes
      Speeds | 16x2445.406
      Models | 16xAMD EPYC 7J13 64-Core Processor
      Caches | 16x512 KB
# Memory #####################################################
       Total | 117.4G
        Free | 8.6G
        Used | physical = 1.4G, swap allocated = 8.0G, swap used = 5.3G, virtual = 6.6G
      Shared | 3.6G
     Buffers | 107.4G
      Caches | 111.3G
       Dirty | 72 kB
     UsedRSS | 1.2G
  Swappiness | 60
 DirtyPolicy | 20, 10

-- build details

cat docs/INFO_SRC
commit: 4e7d422ffbb4fff9342a568b999e44eccc9630dd
date: 2023-12-12 19:05:31 +0100
build-date: 2023-12-12 18:11:09 +0000
short: 4e7d422ffbb
branch: mysql-8.0.36-release

MySQL source 8.0.36

-- startup

rm -rf 114092/
bin/mysqld --no-defaults --initialize-insecure --basedir=$PWD --datadir=$PWD/114092 --log-error-verbosity=3
bin/mysqld_safe --no-defaults --mysqld-version='' --basedir=$PWD --datadir=$PWD/114092 --core-file --socket=/tmp/mysql.sock  --port=3306 --log-error=$PWD/114092/log.err --mysqlx=0 --log-error-verbosity=3  --secure-file-priv="" --local-infile=1  2>&1 &

bin/mysql -uroot -S /tmp/mysql.sock
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 7
Server version: 8.0.36 MySQL Community Server - GPL

Copyright (c) 2000, 2024, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> create user bug@'ip';
Query OK, 0 rows affected (0.00 sec)

mysql> grant all on test.* to  bug@'100.103.30.87';
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE DATABASE IF NOT EXISTS test;
Query OK, 1 row affected (0.01 sec)

mysql> use test;
Database changed
mysql> DROP PROCEDURE IF EXISTS `prepare_data`;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> DELIMITER $$
mysql> CREATE DEFINER=`bug`@`ip` PROCEDURE `prepare_data`()
    -> BEGIN
    ->   DECLARE i INT DEFAULT 1;
    ->   WHILE i < 1000000 DO
    ->     INSERT INTO _TEST (dec_ , var1_) VALUES (ROUND(-1+2*RAND(),2), CONCAT(UUID(), UUID(), UUID(), UUID(), UUID()));
    ->     SET i = i + 1;
    ->   END WHILE;
    -> END$$
Query OK, 0 rows affected (0.00 sec)

mysql> DELIMITER ;
mysql> -- Create test data
mysql> DROP TABLE IF EXISTS _TEST;
Query OK, 0 rows affected, 1 warning (0.01 sec)

mysql> CREATE TABLE `_TEST` (
    ->    `dec_` decimal(15,2) DEFAULT NULL,
    ->    `var1_` varchar(250) DEFAULT NULL
    ->  ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Query OK, 0 rows affected (0.00 sec)

mysql> -- call procedure
mysql>
mysql> CALL prepare_data();
Query OK, 1 row affected (21 min 28.43 sec)

mysql> pager grep less
PAGER set to 'grep less'
mysql>
mysql>  -- Run tests
mysql>
mysql> SELECT * FROM _TEST WHERE dec_ < 0;
496743 rows in set (0.97 sec)

mysql> ALTER TABLE _TEST ADD INDEX dec_(dec_);
Query OK, 999999 rows affected (2.91 sec)
Records: 999999  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM _TEST WHERE dec_ < 0;
496743 rows in set (0.97 sec)

mysql> ALTER TABLE _TEST DROP INDEX dec_;
Query OK, 999999 rows affected (1.68 sec)
Records: 999999  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM _TEST WHERE dec_ < 0;
496743 rows in set (0.98 sec)

regards,
Umesh
[23 Feb 14:49] Daniel Bircher
Hi Umesh,

I appreciate your quick response.  I will attach my config file.  Upon further testing this morning the issue appears to be related to read_rnd_buffer_size.  When specifying a specific value the issue appears - 5GB in my instance.  Please let me know if I can help with anything further. 

Thanks again!
[23 Feb 14:53] Daniel Bircher
When attempting to upload a file, I receive "You don't have permission to access "http://splash.oracle.com/bug.php?" on this server.".  I will paste here:

#
# The MySQL database server configuration file.
#
# One can use all long options that the program supports.
# Run program with --help to get a list of available options and with
# --print-defaults to see which it would actually understand and use.
#
# For explanations see
# http://dev.mysql.com/doc/mysql/en/server-system-variables.html

# Here is entries for some specific programs
# The following values assume you have at least 32M ram

[mysqld]
#
# * Basic Settings
#
user		= mysql
# pid-file	= /var/run/mysqld/mysqld.pid
# socket	= /var/run/mysqld/mysqld.sock
# port		= 3306
# datadir	= /var/lib/mysql

# If MySQL is running as a replication slave, this should be
# changed. Ref https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_tmpdir
# tmpdir		= /tmp
#
# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
bind-address		= 0.0.0.0
mysqlx-bind-address	= 0.0.0.0
#
# * Fine Tuning
#

## *********  Server specifics  ********** ##
disable_log_bin
skip-external-locking
skip-name-resolve
local_infile               = 1
#sql_mode                  = ''
lock_wait_timeout          = 5
max_connections            = 100
default_storage_engine     = MyISAM
default_tmp_storage_engine = MyISAM
event_scheduler            = OFF
big_tables                 = ON

## *********  MyISAM specifics  ********** ##
key_buffer_size           = 5368709120  ##5GB
#read_rnd_buffer_size      = 5368709120  ##5GB

## **********  InnoDB specifics (temp tables)  *********** ##
innodb_tmpdir                  = /var/temp
innodb_temp_tablespaces_dir    = /var/temp
innodb_data_file_path          = ibdata1:10M:autoextend
innodb_buffer_pool_size        = 48G
#innodb_flush_log_at_trx_commit = 0
#innodb_flush_method            = O_DIRECT
#innodb_read_io_threads         = 8
#innodb_write_io_threads        = 8
innodb_buffer_pool_instances   = 48

# This replaces the startup script and checks MyISAM tables if needed
# the first time they are touched
myisam-recover-options  = BACKUP

# max_connections        = 151
# table_open_cache       = 4000

#
# * Logging and Replication
#
# Both location gets rotated by the cronjob.
#
# Log all queries
# Be aware that this log type is a performance killer.
# general_log_file        = /var/log/mysql/query.log
# general_log             = 1
#
# Error log - should be very few entries.
#
log_error = /var/log/mysql/error.log
#
# Here you can see queries with especially long duration
# slow_query_log		= 1
# slow_query_log_file	= /var/log/mysql/mysql-slow.log
# long_query_time = 2
# log-queries-not-using-indexes
#
# The following can be used as easy to replay backup logs or for replication.
# note: if you are setting up a replication slave, see README.Debian about
#       other settings you may need to change.
# server-id		= 1
# log_bin			= /var/log/mysql/mysql-bin.log
# binlog_expire_logs_seconds	= 2592000
# max_binlog_size   = 100M
# binlog_do_db		= include_database_name
# binlog_ignore_db	= include_database_name
[24 Feb 12:05] MySQL Verification Team
Thank you, Daniel for the details.
I'm able to reproduce after setting read_rnd_buffer_size to 5G. Let me check with other storage engine to see if it affects just MyISAM or other also. Thank you once again for sharing the conf file.

Sincerely,
Umesh
[24 Feb 13:55] Daniel Bircher
Thank you, Umesh.  Please let me know if there's anything else I can do to support the resolution of this big.