0

related to MySQL tuning (my.cnf) for very large tables and ad hoc queries

I have a really small table with 2M records, on a 32GB machine, running Windows 10 Pro with nothing serious running except MySql 5.7. I expected that simple group by on any un-indexed column would take seconds, as Mysql would cache the entire table. It takes about 3 minutes. Am I missing some important tuning tip? or are these the expected times?

the query

mysql> select specialty_code, count(*)
    -> from physicians
    -> group by specialty_code;
+----------------+----------+
| specialty_code | count(*) |
+----------------+----------+
| FM             |   199604 |
| GYN            |    14263 |
| OBG            |    78878 |
+----------------+----------+
3 rows in set (2 min 56.27 sec)

the table

mysql> describe physicians;
+-----------------------+---------+------+-----+---------+-------+
| Field                 | Type    | Null | Key | Default | Extra |
+-----------------------+---------+------+-----+---------+-------+
| physician_id          | int(11) | YES  |     | NULL    |       |
| practitioner_id       | int(11) | YES  | MUL | NULL    |       |
| state                 | text    | YES  |     | NULL    |       |
| specialty_code        | text    | YES  |     | NULL    |       |
| specialty_description | text    | YES  |     | NULL    |       |
| CBSA                  | text    | YES  |     | NULL    |       |
+-----------------------+---------+------+-----+---------+-------+
6 rows in set (0.10 sec)    

mysql> show table status like '%physicians%';
+------------+--------+---------+------------+---------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+-----------------+----------+----------------+---------+
| Name       | Engine | Version | Row_format | Rows    | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Create_time         | Update_time | Check_time | Collation       | Checksum | Create_options | Comment |
+------------+--------+---------+------------+---------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+-----------------+----------+----------------+---------+
| physicians | InnoDB |      10 | Dynamic    | 1963005 |             66 |   130711552 |               0 |            0 |   2097152 |           NULL | 2016-01-04 08:41:30 | NULL        | NULL       | utf8_general_ci |     NULL |                |         |
+------------+--------+---------+------------+---------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+-----------------+----------+----------------+---------+

sizing:

mysql> select count(*) from physicians;
+----------+
| count(*) |
+----------+
|  1957997 |
+----------+
1 row in set (9.91 sec) 

explain:

mysql> explain select specialty_code, count(*)
    -> from physicians
    -> group by specialty_code;
+----+-------------+------------+------------+------+---------------+------+---------+------+---------+----------+---------------------------------+
| id | select_type | table      | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra                           |
+----+-------------+------------+------------+------+---------------+------+---------+------+---------+----------+---------------------------------+
|  1 | SIMPLE      | physicians | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 1963005 |   100.00 | Using temporary; Using filesort |
+----+-------------+------------+------------+------+---------------+------+---------+------+---------+----------+---------------------------------+    

params I tuned:

join_buffer_size=2G 
tmp_table_size=5G
innodb_buffer_pool_size=20G
sort_buffer_size=2G

The table uses the default InnoDB engine.

NOTE: this is just a simplified symptom of my bigger problem: I have ~5-6 tables with a total volume of 10 GB. I expected MySql to swoosh all of them into the memory and answer any ad-hoc query within a minute or so... Should I index every column before filtering/grouping/joining on it?

Thanks and sorry if this is ranting. I'm just used to distributed databases crunching data in milliseconds for me :)

3
  • 2
    The Using temporary together with a TEXT column for grouping means on-disk (MyISAM) temporary table, so lot of disk IO. You might put the temp dir for those on some ram disk as a quick and dirty solution, but seeing the results only contains max 3 characters in the column, you should probably restructure the table a bit, use (VAR)CHAR(3), ENUM or maybe a lookup table (smallint foreign key) for that column. Check the other columns too if they need to be TEXT.
    – jkavalik
    Commented Jan 4, 2016 at 9:14
  • Revert the changes to join_buffer_size and sort_buffer_size - those are allocated per-thread (connected client) so can hurt performance badly and even crash/kill mysql because of not enough memory. Revert the tmp_table_size setting too, it can only work in combination with max_heap_table_size and only for some tables (and the TEXT column explicitly forces the on-disk table anyway)
    – jkavalik
    Commented Jan 4, 2016 at 9:19
  • thanks @jkavalik, about the buffers - I've checked and there's no swap happening, MySql is taking tops 20G out of my 30G with all those settings, so no worries there. I'm the only user connecting and there's only 1 session.
    – ihadanny
    Commented Jan 4, 2016 at 9:32

1 Answer 1

3

tmp_table_size=5G

No. Go back to the default. If multiple queries need tmp tables, you could run out of RAM.

Change the TEXT fields to reasonable-length VARCHARs.

The first table scan will do I/O to bring the table into RAM (if possible); subsequent references to the table will see the data cached. Did you run the GROUP BY twice to see this effect?

5
  • Thanks @rick-james, about tmp_table_size - even if I can be absolutely sure that I'm the only one connecting to this db, and only one session would be active at any given moment? I checked and there's plenty of RAM left....
    – ihadanny
    Commented Jan 5, 2016 at 8:45
  • OK 5G is harmless today. If, as the data and activity grows, you suddenly get a massive slowdown, reach for that setting.
    – Rick James
    Commented Jan 5, 2016 at 17:49
  • @ihadanny Did you see an improvement on the second run? What happened? I'm also used to distributed datastores and have no idea what to expect from mysql
    – Riley Lark
    Commented Feb 16, 2016 at 16:07
  • @RileyLark , I did see an improvement once I stopped using TEXT fields, which was just wrong. However, I was way off-mark with my lousy 32GB machine :) Turns out nowadays people use bigger beasts to host their data. See this thread with smart insights: kaggle.com/c/cervical-cancer-screening/forums/t/18693/…
    – ihadanny
    Commented Feb 16, 2016 at 16:24
  • (Re @RileyLark 's sampling) If you are experimenting with algorithms, theories, etc, why not have 2 small tables with random subsets of the data -- experiment with one table, test with the other, then finally check with the big table.
    – Rick James
    Commented Feb 16, 2016 at 22:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.