mysql> SELECT SQL_NO_CACHE COUNT(rb.subscription_id) as
recurring_cc_count,
-> SUM(rb.grace_price) as recurring_cc,
-> COUNT(sb.subscription_id) as single_cc_count,
-> SUM(sb.initial_amt) as single_cc
-> FROM customerdetail a
-> LEFT JOIN recurringbilling rb
-> ON a.subscription_id = rb.subscription_id
-> LEFT JOIN singlebilling sb
-> ON a.subscription_id = sb.subscription_id
-> LEFT JOIN (global.subscriptionExchangeRate as ser INNER JOIN
global.currencyCodes as cur)
-> ON (a.subscription_id = ser.subscriptionId AND
ser.billedCurrencyCode = cur.currencyCode)
-> WHERE client_accnum = '12345'
-> AND a.trans_timestamp
-> BETWEEN '20070108000000' AND '20070108235959';
+--------------------+--------------+-----------------+-----------+
| recurring_cc_count | recurring_cc | single_cc_count | single_cc |
+--------------------+--------------+-----------------+-----------+
| 4 | 119.80 | 0 | NULL |
+--------------------+--------------+-----------------+-----------+
1 row in set (0.40 sec)
mysql> explain SELECT SQL_NO_CACHE COUNT(rb.subscription_id) as
recurring_cc_count,
-> SUM(rb.grace_price) as recurring_cc,
-> COUNT(sb.subscription_id) as single_cc_count,
-> SUM(sb.initial_amt) as single_cc
-> FROM customerdetail a
-> LEFT JOIN recurringbilling rb
-> ON a.subscription_id = rb.subscription_id
-> LEFT JOIN singlebilling sb
-> ON a.subscription_id = sb.subscription_id
-> LEFT JOIN (global.subscriptionExchangeRate as ser INNER JOIN
global.currencyCodes as cur)
-> ON (a.subscription_id = ser.subscriptionId AND
ser.billedCurrencyCode = cur.currencyCode)
-> WHERE client_accnum = '12345'
-> AND a.trans_timestamp
-> BETWEEN '20070108000000' AND '20070108235959';
+----+-------------+-------+--------+-----------------------------------
-----------------------------+-----------------+---------+--------------
-----------------+------+--------------------------+
| id | select_type | table | type | possible_keys
| key | key_len | ref | rows |
Extra |
+----+-------------+-------+--------+-----------------------------------
-----------------------------+-----------------+---------+--------------
-----------------+------+--------------------------+
| 1 | SIMPLE | a | range |
client_idx,trans_idx,accno_trans_idx,accnumactive,accsubactive |
accno_trans_idx | 7 | NULL | 4 | Using
where; Using index |
| 1 | SIMPLE | rb | eq_ref | PRIMARY
| PRIMARY | 8 | company.a.subscription_id | 1 |
|
| 1 | SIMPLE | sb | eq_ref | PRIMARY
| PRIMARY | 8 | company.a.subscription_id | 1 |
|
| 1 | SIMPLE | ser | ref | PRIMARY,billedCurrencyCode
| PRIMARY | 8 | company.a.subscription_id | 1 |
|
| 1 | SIMPLE | cur | eq_ref | PRIMARY
| PRIMARY | 2 | global.ser.billedCurrencyCode | 1 |
Using index |
+----+-------------+-------+--------+-----------------------------------
-----------------------------+-----------------+---------+--------------
-----------------+------+--------------------------+
5 rows in set (0.00 sec)
mysql> show index from customerdetail;
+----------------+------------+-----------------+--------------+--------
---------+-----------+-------------+----------+--------+------+---------
---+---------
+
| Table | Non_unique | Key_name | Seq_in_index |
Column_name | Collation | Cardinality | Sub_part | Packed | Null |
Index_type | Comment
|
+----------------+------------+-----------------+--------------+--------
---------+-----------+-------------+----------+--------+------+---------
---+---------
..........................SNIP........................................
| customerdetail | 1 | accno_trans_idx | 1 |
client_accnum | A | 17052 | NULL | NULL | |
BTREE |
|
| customerdetail | 1 | accno_trans_idx | 2 |
trans_timestamp | A | 49042196 | NULL | NULL | |
BTREE |
..........................SNIP........................................
+----------------+------------+-----------------+--------------+--------
---------+-----------+-------------+----------+--------+------+---------
---+---------+
The query executes orders of magnitude faster, and the EXPLAIN shows
why. MySQL has now chosen to use the accno_trans_idx index for the
customerdetail table which has much better cardinality (almost 1 key per
row).
The obvious workaround is use FORCE INDEX(accno_trans_idx) in the query
for now, but I'm beginning to think this may be a bug. Has anyone else
had any similar issues? I haven't found anything like this in the bug
database though. If anyone doesn't see anything blatantly wrong with my
setup, I'll submit this as a bug.
Further information:
Here is how MySQL is configured, and the my.cnf I'm using.
CC="gcc -m64" CXX="g++ -m64" \
./configure --prefix=/usr \
--sbindir=/usr/sbin \
--libexecdir=/usr/sbin \
--infodir=/usr/share/man \
--mandir=/usr/share/info \
--libdir=/usr/lib64 \
--enable-shared \
--enable-static \
--enable-thread-safe-client \
--enable-local-infile \
--with-extra-charsets=all \
--with-gnu-ld \
--with-pthread \
--with-unix-socket-path=/tmp/mysql.sock \
--with-mysqld-user=mysql \
--without-debug \
--with-openssl=/usr \
--with-big-tables \
--with-archive-storage-engine \
--with-csv-storage-engine \
--with-blackhole-storage-engine \
--with-federated-storage-engine \
--with-berkeley-db \
--with-berkeley-includes=/usr/include \
--with-berkeley-libs=/usr/lib64 \
--without-extra-tools \
--with-mysqlmanager=no \
--with-ndbcluster \
--without-geometry
----------------------
[mysqld]
#Directories
datadir=/var/db/mysql
socket=/tmp/mysql.sock
log-error=/var/log/mysql/mysql.log
pid-file=/var/run/mysqld/mysqld.pid
tmpdir=/tmp
#Replication
server-id=127
#log-bin=
replicate-ignore-db=mysql
#log-slave-updates
#Network
max_connections=1024
max_allowed_packet=1024M
net_buffer_length=16k
#Files
open_files_limit=8192 # Anything higher needs corresponding ulimit entry
#Buffers
join_buffer_size=128M
key_buffer_size=512M
key_buffer=512M
large_pages
max_heap_table_size=1024M
myisam_sort_buffer_size=256M
read_buffer_size=64M
read_buffer=64M
query_cache_size=32M
query_cache_type=1
record_buffer=512
sort_buffer=512M
table_cache=512
thread_cache=4M
thread_stack=512K
thread_cache_size=300
thread_concurrency=16
tmp_table_size=1G
#innodb
innodb-table-locks=off
transaction_isolation=REPEATABLE-READ
innodb_buffer_pool_size=1024M
innodb_log_buffer_size=8M
innodb_flush_log_at_trx_commit=0
innodb_log_file_size=128M
innodb_additional_mem_pool_size=32M
innodb_thread_concurrency=16
innodb_commit_concurrency=4
innodb_flush_method=O_DIRECT
innodb_open_files=8192
innodb_sync_spin_loops=32
innodb_thread_sleep_delay=1000
innodb_autoextend_increment=1024M
innodb_file_per_table=TRUE
[client]
socket=/tmp/mysql.sock
John Anderson