SELECT query taking too long after MySQL upgrade - mysql

I just updated my MySQL version to 5.7. A SELECT query that has four INNER-JOINS and that previously took around 3 seconds to execute is now taking so long that I can't even keep track of it. A bit of profiling shows that the 'Send Data' part is taking too long. Can someone tell me what is going wrong? Here's some data. Note that the query is still running at this point in time:
+----------------------+-----------+
| Status | Duration |
+----------------------+-----------+
| starting | 0.001911 |
| checking permissions | 0.000013 |
| checking permissions | 0.000003 |
| checking permissions | 0.000003 |
| checking permissions | 0.000006 |
| Opening tables | 0.000030 |
| init | 0.000406 |
| System lock | 0.000018 |
| optimizing | 0.000019 |
| statistics | 0.000509 |
| preparing | 0.000052 |
| executing | 0.000004 |
| Sending data | 31.881794 |
| end | 0.000021 |
| query end | 0.003540 |
| closing tables | 0.000032 |
| freeing items | 0.000214 |
| cleaning up | 0.000028 |
+----------------------+-----------+
Here's the output of EXPLAIN:
+----+-------------+--------------------+------------+------+---------------+------------+---------+-------+---------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------------------+------------+------+---------------+------------+---------+-------+---------+----------+----------------------------------------------------+
| 1 | SIMPLE | movie_data_primary | NULL | ref | cinestopId | cinestopId | 26 | const | 1 | 100.00 | NULL |
| 1 | SIMPLE | mg | NULL | ALL | NULL | NULL | NULL | NULL | 387498 | 10.00 | Using where; Using join buffer (Block Nested Loop) |
| 1 | SIMPLE | crw | NULL | ALL | NULL | NULL | NULL | NULL | 1383452 | 10.00 | Using where; Using join buffer (Block Nested Loop) |
| 1 | SIMPLE | cst | NULL | ALL | NULL | NULL | NULL | NULL | 2184556 | 10.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+--------------------+------------+------+---------------+------------+---------+-------+---------+----------+----------------------------------------------------+

Looks like indexing problem when you upgrade the msssql version-
Documentation says-
If you perform a binary upgrade without dumping and reloading tables,
you cannot upgrade directly from MySQL 4.1 to 5.1 or higher. This
occurs due to an incompatible change in the MyISAM table index
formatin MySQL 5.0. Upgrade from MySQL 4.1 to 5.0 and repair all
MyISAM tables. Then upgrade from MySQL 5.0 to 5.1 and check and
repair your tables.Modifications to the handling of character sets or
collations might change the character sort order, which causes the
ordering of entries in any index that uses an affected character
set or collation to be incorrect. Such changes result in several
possible problems: Comparison results that differ from previous
results
Inability to find some index values due to misordered index entries
Misordered ORDER BY results
Tables that CHECK TABLE reports as being in need of repair
Check for the links-
1)checking-table-incompatibilities
2)check-table
3)rebuilding-tables

Related

Simple query: mysql - very slow , mariadb - good performance

Simple query:
select *
from data.staff AS staff
left join data.contact AS workphones on staff.id = workphones.staff_with_work_phone_id
Mysql run time: 5.3 sec.
MariaDb run time: 0.016 sec.
Contact has ~50000 rows.
Staff has ~600 rows.
What is the reason?
Is it possible to achieve the same result on mysql?
Thank you!
Explain MySql (v5.7.14):
+----+-------------+------------+------------+------+--------------------------------+------+---------+------+-------+----------+---------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+------------+------+--------------------------------+------+---------+------+-------+----------+---------------------------------------+
| 1 | SIMPLE | staff | NULL | ALL | NULL | NULL | NULL | NULL | 606 | 100.00 | NULL |
+----+-------------+------------+------------+------+--------------------------------+------+---------+------+-------+----------+---------------------------------------+
| 2 | SIMPLE | workphones | NULL | ALL | FK_2f7824065c2c4b0fbe5c00da271 | NULL | NULL | NULL | 49180 | 100.00 | Using where. |
| | | | | | | | | | | | Using join buffer (Block Nested Loop) |
+----+-------------+------------+------------+------+--------------------------------+------+---------+------+-------+----------+---------------------------------------+
Explain MariaDB (v10.0.28):
+----+-------------+------------+------+--------------------------------+--------------------------------+---------+--------------------+-------+----------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+------+--------------------------------+--------------------------------+---------+--------------------+-------+----------+-------+
| 1 | SIMPLE | staff | ALL | | | | | 602 | 100.00 | |
+----+-------------+------------+------+--------------------------------+--------------------------------+---------+--------------------+-------+----------+-------+
| 2 | SIMPLE | workphones | ALL | FK_1249f6bc1d68495090691f3ce02 | FK_1249f6bc1d68495090691f3ce02 | 9 | user_data.staff.id | 25476 | 100.00 | |
+----+-------------+------------+------+--------------------------------+--------------------------------+---------+--------------------+-------+----------+-------+
The rest of the verification conditions are identical.
The test was conducted many times.
Your two query plans show you why MySQL is slower.
Both find the possible keys, which is a foreign key.
MariaDB will USE the FK: FK_1249f6bc1d68495090691f3ce02 is in both columns possible_keys AND keys in row 2.
MySQL does see the FK, but does NOT use it.
MySQL tells you, that it will use a
Using join buffer (Block Nested Loop)
in the EXTRA table.
MySQL does not use your Foreign Key.
Foreign Key Joins
Do you have an index on your foreign key in both database systems?
If only MariaDB has it, then you cannot blame MySQL, because it cannot use, what it does not have.

Index not used in query. How to improve performance?

I have this query:
SELECT
*
FROM
`av_cita`
JOIN `av_cita_cstm` ON (
(
`av_cita`.`id` = `av_cita_cstm`.`id_c`
)
)
WHERE
av_cita.deleted = 0
This query takes over 120 seconds to finish, yet I have added all indexes.
When I ask for the execution plan:
explain SELECT * FROM `av_cita`
JOIN `av_cita_cstm` ON ( ( `av_cita`.`id` = `av_cita_cstm`.`id_c` ) )
WHERE av_cita.deleted = 0;
I get this:
+----+-------------+--------------+--------+----------------------+---------+---------+---------------------------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------+--------+----------------------+---------+---------+---------------------------+--------+-------------+
| 1 | SIMPLE | av_cita | ALL | PRIMARY,delete_index | NULL | NULL | NULL | 192549 | Using where |
| 1 | SIMPLE | av_cita_cstm | eq_ref | PRIMARY | PRIMARY | 108 | rednacional_v2.av_cita.id | 1 | |
+----+-------------+--------------+--------+----------------------+---------+---------+---------------------------+--------+-------------+
delete_index is listed in the possible_keys column, but the key is null, and it doesn't use the index.
Table and index definitions:
+------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------+--------------+------+-----+---------+-------+
| id | char(36) | NO | PRI | NULL | |
| name | varchar(255) | YES | MUL | NULL | |
| date_entered | datetime | YES | MUL | NULL | |
| date_modified | datetime | YES | | NULL | |
| modified_user_id | char(36) | YES | | NULL | |
| created_by | char(36) | YES | MUL | NULL | |
| description | text | YES | | NULL | |
| deleted | tinyint(1) | YES | MUL | 0 | |
| assigned_user_id | char(36) | YES | MUL | NULL | |
+------------------+--------------+------+-----+---------+-------+
+---------+------------+--------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------+------------+--------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| av_cita | 0 | PRIMARY | 1 | id | A | 192786 | NULL | NULL | | BTREE | | |
| av_cita | 1 | delete_index | 1 | deleted | A | 2 | NULL | NULL | YES | BTREE | | |
| av_cita | 1 | name_index | 1 | name | A | 96393 | NULL | NULL | YES | BTREE | | |
| av_cita | 1 | date_entered_index | 1 | date_entered | A | 96393 | NULL | NULL | YES | BTREE | | |
| av_cita | 1 | created_by | 1 | created_by | A | 123 | NULL | NULL | YES | BTREE | | |
| av_cita | 1 | assigned_user_id | 1 | assigned_user_id | A | 1276 | NULL | NULL | YES | BTREE | | |
| av_cita | 1 | deleted_id | 1 | deleted | A | 2 | NULL | NULL | YES | BTREE | | |
| av_cita | 1 | deleted_id | 2 | id | A | 192786 | NULL | NULL | | BTREE | | |
| av_cita | 1 | id | 1 | id | A | 192786 | NULL | NULL | | BTREE | | |
+---------+------------+--------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
How can I improve the performance of this query?
The query is losing time on making the join. I would strongly suggest to create and index on av_cita_cstm.id_c. Then the plan will probably be changed to use that index for the av_cita_cstm table, which is much better than PRIMARY. As a consequence PRIMARY will be used on ac_cita.
I think that will bring a big improvement. You might still get more improvement if you make sure delete_index is defined with two fields: (deleted, id), and then move the where condition of the SQL statement into the join condition. But I am not sure MySql will see this as a possibility.
The index on deleted is not used probably because the optimizer has decided that a full table-scan is cheaper than using the index. MySQL tends to make this decision if the value you search for is found on about 20% or more of the rows in the table.
By analogy, think of the index at the back of a book. You can understand why common words like "the" aren't indexed. It would be easier to just read the book cover-to-cover than to flip back and forth to the index, which only tells you that "the" appears on a majority of pages.
If you think MySQL has made the wrong decision, you can make it pretend that a table-scan is more expensive than using a specific index:
SELECT
*
FROM
`av_cita` FORCE INDEX (deleted_index)
JOIN `av_cita_cstm` ON (
(
`av_cita`.`id` = `av_cita_cstm`.`id_c`
)
)
WHERE
av_cita.deleted = 0
Read http://dev.mysql.com/doc/refman/5.7/en/index-hints.html for more information about index hints. Don't overuse index hints, they're useful only in rare cases. Most of the time the optimizer makes the right decision.
Your EXPLAIN plan shows that your join to av_cita_cstm is already using a unique index (the clue is "type: eq_ref" and also the "rows: 1"). I don't think any new index is needed in that table.
I notice the EXPLAIN shows that the table-scan on av_cita scans about an estimated 192549 rows. I'm really surprised that this takes 120 seconds. On any reasonably powerful computer, that should run much faster.
That makes me wonder if you have something else that needs tuning or configuration on this server:
What other processes are running on the server? A lot of applications, perhaps? Are the other processes also running slowly on this server? Do you need to increase the power of the server, or move applications onto their own server?
If you're on MySQL 5.7, try querying the sys schema: this:
select * from sys.innodb_buffer_stats_by_table
where object_name like 'av_cita%';
Are there other costly SQL queries running concurrently?
Did you under-allocate MySQL's innodb_buffer_pool_size? If it's too small, it could be furiously recycling pages in RAM as it scans your table.
select ##innodb_buffer_pool_size;
Did you over-allocate innodb_buffer_pool_size? Once I helped tune a server that was running very slowly. It turned out they had a 4GB buffer pool, but only 1GB of physical RAM. The operating system was swapping like crazy, causing everything to run slowly.
Another thought: You have shown us the columns in av_cita, but not the table structure for av_cita_cstm. Why are you fetching SELECT *? Do you really need all the columns? Are there huge BLOB/TEXT columns in the latter table? If so, it could be reading a large amount of data from disk that you don't need.
When you ask SQL questions, it would help if you run
SHOW CREATE TABLE av_cita\G
SHOW TABLE STATUS LIKE 'av_cita'\G
And also run the same commands for the other table av_cita_cstm, and include the output in your question above.

Slow query times on AWS RDS but not on DigitalOcean LAMP

I have a database dump and MySQL query that is the same across three environments, but it is extremely slow on AWS, and I'd like to find out why.
Query runs 15s ~ 30s on AWS RDS but 8ms ~ 12ms on DigitalOcean LAMP. (Control experiment: Local MAMP stack runs 8s ~ 10s).
How is this possible that DigitalOcean LAMP stack is running the same query in ms?
Backstory: I migrated from DigitalOcean to AWS RDS. I am super shocked at the query speeds. I can't figure out why.
Note: Using T2.micro RDS instance. Have also tested with M4.2xLarge RDS instance. Query times are the same.
Here is the query:
SELECT `t`.`col1` AS `t0_c0`,
`t`.`col2` AS `t0_c1`,
`t`.`col3` AS `t0_c2`,
`t`.`col4` AS `t0_c3`,
`t`.`col5` AS `t0_c4`,
`t`.`col6` AS `t0_c5`,
`t`.`col7` AS `t0_c6`,
`t`.`col8` AS `t0_c7`,
`t`.`col9` AS `t0_c8`,
`t`.`col10` AS `t0_c9`,
`t`.`col11` AS `t0_c10`,
`t`.`col12` AS `t0_c11`,
`t`.`col13` AS `t0_c12`,
`t`.`col14` AS `t0_c13`,
`t`.`col15` AS `t0_c14`,
`t`.`col16` AS `t0_c15`,
`t`.`col17` AS `t0_c16`,
`t`.`col18` AS `t0_c17`,
`t`.`col19` AS `t0_c18`,
`t`.`col20` AS `t0_c19`,
`t`.`col21` AS `t0_c20`,
`t`.`col22` AS `t0_c21`,
`t`.`col23` AS `t0_c22`,
`t`.`col24` AS `t0_c23`,
`t`.`col25` AS `t0_c24`,
`t`.`col26` AS `t0_c25`,
`t`.`col27` AS `t0_c26`,
`t`.`col28` AS `t0_c27`,
`t`.`col29` AS `t0_c28`,
`t`.`col30` AS `t0_c29`,
`t`.`col31` AS `t0_c30`,
`t`.`col32` AS `t0_c31`,
`t`.`col33` AS `t0_c32`,
`t`.`col34` AS `t0_c33`,
`t`.`col35` AS `t0_c34`,
`t`.`col36` AS `t0_c35`,
`t`.`col37` AS `t0_c36`,
`t`.`col38` AS `t0_c37`,
`t`.`col39` AS `t0_c38`,
`t`.`col40` AS `t0_c39`,
`t`.`col41` AS `t0_c40`,
`t`.`col42` AS `t0_c41`,
`t`.`col43` AS `t0_c42`,
`t`.`col44` AS `t0_c43`,
`t`.`col45` AS `t0_c44`,
`t`.`col46` AS `t0_c45`,
`t`.`col47` AS `t0_c46`,
`t`.`col48` AS `t0_c47`,
`t`.`col49` AS `t0_c48`,
COUNT(exactTagMatch.id) AS exactMatches,
COUNT(tags.id) AS matches,
`vendor`.`col1` AS `t1_c0`,
`vendor`.`col2` AS `t1_c1`,
`vendor`.`col3` AS `t1_c2`,
`vendor`.`col4` AS `t1_c3`,
`vendor`.`col5` AS `t1_c4`,
`vendor`.`col6` AS `t1_c5`,
`vendor`.`col7` AS `t1_c6`,
`vendor`.`col8` AS `t1_c7`,
`vendor`.`col9` AS `t1_c8`,
`vendor`.`col10` AS `t1_c9`,
`vendor`.`col11` AS `t1_c10`,
`vendor`.`col12` AS `t1_c11`,
`vendor`.`col13` AS `t1_c12`,
`vendor`.`col14` AS `t1_c13`,
`vendor`.`col15` AS `t1_c14`,
`vendor`.`col16` AS `t1_c15`,
`vendor`.`col17` AS `t1_c16`,
`vendor`.`col18` AS `t1_c17`,
`vendor`.`col19` AS `t1_c18`,
`vendor`.`col20` AS `t1_c19`,
`vendor`.`col21` AS `t1_c20`,
`vendor`.`col22` AS `t1_c21`,
`vendor`.`col23` AS `t1_c22`,
`vendor`.`col24` AS `t1_c23`,
`vendor`.`col25` AS `t1_c24`,
`vendor`.`col26` AS `t1_c25`,
`vendor`.`col27` AS `t1_c26`,
`vendor`.`col28` AS `t1_c27`,
`tags`.`col1` AS `t2_c0`,
`tags`.`col2` AS `t2_c1`,
`tags`.`col3` AS `t2_c2`,
`tags`.`col4` AS `t2_c3`,
`tags`.`col5` AS `t2_c4`,
`tags`.`col6` AS `t2_c5`,
`tags`.`col7` AS `t2_c6`,
`tags`.`col8` AS `t2_c7`,
`tags`.`col9` AS `t2_c8`,
`tags`.`col10` AS `t2_c9`,
`tags`.`col11` AS `t2_c10`,
`tags`.`col12` AS `t2_c11`
FROM `table1` `t`
LEFT JOIN table3 AS exactTagMatch ON exactTagMatch.col1 = 1545
AND exactTagMatch.col1 = t.col1
LEFT OUTER JOIN `table2` `vendor` ON (`t`.`col1`=`vendor`.`id`)
LEFT OUTER JOIN `table3` `tags_tags` ON (`t`.`col1`=`tags_tags`.`col1`)
LEFT OUTER JOIN `table3` `tags` ON (`tags`.`id`=`tags_tags`.`col1`)
WHERE (((((t.col2 LIKE '%search query%')
OR (vendor.col2 LIKE '%search query%'))
OR (tags.col1 IN ('1386',
'1407',
'1408',
'1409',
'1410',
'1411',
'1416',
'1418',
'1512',
'1519',
'1528',
'1545',
'1583',
'1584',
'1585',
'1586',
'1604',
'1605')))
AND (t.col2='active'))
AND (t.col3='0'))
GROUP BY t.col1
ORDER BY exactMatches DESC,
matches DESC,
t.col5 DESC LIMIT 12;
MySQL Plan: AWS RDS (Slow)
+----+-------------+---------------+--------+---------------------------------+-------------------------+---------+-----------------------+-------+--------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------------+--------+---------------------------------+-------------------------+---------+-----------------------+-------+--------------------------------------------------------+
| 1 | SIMPLE | t | ref | PRIMARY,activity_status_premium | activity_status_premium | 2 | const,const | 594 | Using index condition; Using temporary; Using filesort |
| 1 | SIMPLE | exactTagMatch | ALL | NULL | NULL | NULL | NULL | 24434 | Using where; Using join buffer (Block Nested Loop) |
| 1 | SIMPLE | vendor | eq_ref | PRIMARY | PRIMARY | 4 | ebdb.t.vendor_id | 1 | NULL |
| 1 | SIMPLE | tags_tags | ALL | NULL | NULL | NULL | NULL | 24434 | Using where; Using join buffer (Block Nested Loop) |
| 1 | SIMPLE | tags | eq_ref | PRIMARY | PRIMARY | 4 | ebdb.tags_tags.tag_id | 1 | Using where |
+----+-------------+---------------+--------+---------------------------------+-------------------------+---------+-----------------------+-------+--------------------------------------------------------+
5 rows in set (0.02 sec)
MySQL Plan: DigitalOcean (Fast)
+----+-------------+---------------+--------+-------------------------+-------------------------+---------+-------------------------------+-------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------------+--------+-------------------------+-------------------------+---------+-------------------------------+-------+----------------------------------------------+
| 1 | SIMPLE | t | ref | activity_status_premium | activity_status_premium | 2 | const,const | 590 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | exactTagMatch | ALL | NULL | NULL | NULL | NULL | 32473 | |
| 1 | SIMPLE | vendor | eq_ref | PRIMARY | PRIMARY | 4 | db.t.vendor_id | 1 | |
| 1 | SIMPLE | tags_tags | ALL | NULL | NULL | NULL | NULL | 32473 | |
| 1 | SIMPLE | tags | eq_ref | PRIMARY | PRIMARY | 4 | db.tags_tags.tag_id | 1 | Using where |
+----+-------------+---------------+--------+-------------------------+-------------------------+---------+-------------------------------+-------+----------------------------------------------+
5 rows in set (0.01 sec)
Here is a comparison between the MySQL versions:
MySQL Version: AWS RDS (Slow)
mysql> SHOW VARIABLES LIKE "%version%";
+-------------------------+------------------------------+
| Variable_name | Value |
+-------------------------+------------------------------+
| innodb_version | 5.6.27 |
| protocol_version | 10 |
| slave_type_conversions | |
| version | 5.6.27 |
| version_comment | MySQL Community Server (GPL) |
| version_compile_machine | x86_64 |
| version_compile_os | Linux |
+-------------------------+------------------------------+
7 rows in set (0.03 sec)
MySQL Version: DigitalOcean (Fast)
mysql> SHOW VARIABLES LIKE "%version%";
+-------------------------+-------------------------+
| Variable_name | Value |
+-------------------------+-------------------------+
| innodb_version | 5.5.44 |
| protocol_version | 10 |
| slave_type_conversions | |
| version | 5.5.44-0ubuntu0.14.04.1 |
| version_comment | (Ubuntu) |
| version_compile_machine | x86_64 |
| version_compile_os | debian-linux-gnu |
+-------------------------+-------------------------+
7 rows in set (0.01 sec)
Here is a comparison between the .cnf files: https://www.diffnow.com/?report=ze4m0
Note: Had to use external link because body exceeded character count
Update
Just ran more tests. On DigitalOcean, the first time i run the query it took 14s. Thereafter it runs in in ms. I believe there is some sort of caching/indexing going on there. Would like to find out what could result in this.
In MySql 5.6+, the query cache is disabled by default. In your my.cnf files you can see that by looking for "query_cache_type" - you'll see it's OFF on RDS, but not on the DO db.
I'd bet that if you run the query for the first time on DO it will be a similar speed - no other conf change is likely to result in such dramatic differences.
As the cache is off now by default, you should read up on the reasons for that change - it's your call if you need it or not, but just note that it was disabled deliberately!

Mysql takes more time in sending data

I have this particular query which takes long time to execute, other queries on the same tables execute very fast. Querycache is enabled in mysql but still the below query takes more than 80 seconds everytime and CPU crosses 100% utilization.
I cannot modify the query because it is generated by Drupal. Is there anything else I can do to improve performance?
The query is:
select count(*)
from (
SELECT slk.key_id AS key_id
FROM slk slk
LEFT JOIN users users ON slk.uid = users.uid
LEFT JOIN node node_users ON users.uid = node_users.uid
AND node_users.type = 'profile'
) count_alias;
Below is the profile information:
+--------------------------------+-----------+
| Status | Duration |
+--------------------------------+-----------+
| starting | 0.000029 |
| checking query cache for query | 0.000093 |
| Opening tables | 0.000210 |
| System lock | 0.000007 |
| Table lock | 0.000075 |
| optimizing | 0.000008 |
| statistics | 0.000113 |
| preparing | 0.000027 |
| executing | 0.000004 |
| Sending data | 66.086903 |
| init | 0.000027 |
| optimizing | 0.000009 |
| executing | 0.000018 |
| end | 0.000003 |
| query end | 0.000004 |
| freeing items | 0.000049 |
| storing result in query cache | 0.000116 |
| removing tmp table | 0.033162 |
| closing tables | 0.000106 |
| logging slow query | 0.000003 |
| logging slow query | 0.000085 |
| cleaning up | 0.000007 |
+--------------------------------+-----------+
explain on the query gives:
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
| 1 | PRIMARY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away |
| 2 | DERIVED | slk | ALL | NULL | NULL | NULL | NULL | 55862 | |
| 2 | DERIVED | users | eq_ref | PRIMARY | PRIMARY | 4 | gscom.slk.uid | 1 | Using index |
| 2 | DERIVED | node_users | ref | node_type,uid,idx_ctp | uid | 4 | gscom.users.uid | 3 | |
idx_ctp is an index on (uid, type).
The query cache is working and below are the stats.
show variables like '%query_cache%';:
| Variable_name | Value |
| have_query_cache | YES |
| query_cache_limit | 2097152 |
| query_cache_min_res_unit | 4096 |
| query_cache_size | 52428800 |
| query_cache_type | ON |
| query_cache_wlock_invalidate | OFF |
mysql> show status like '%Qcache%';:
| Variable_name | Value |
| Qcache_free_blocks | 1255 |
| Qcache_free_memory | 22902848 |
| Qcache_hits | 1484908 |
| Qcache_inserts | 1036344 |
| Qcache_lowmem_prunes | 95086 |
| Qcache_not_cached | 3975 |
| Qcache_queries_in_cache | 14271 |
| Qcache_total_blocks | 30117 |
You need indexes on:
table slk: (uid)
table node_users: (type, uid)
The query can be rewritten without subquery, as:
SELECT COUNT(*)
FROM slk
LEFT JOIN users
ON slk.uid = users.uid
LEFT JOIN node node_users
ON users.uid = node_users.uid
AND node_users.type = 'profile'
And I'm really not sure why you use LEFT JOIN. You can probably use INNER JOIN and have the same result. Or just use the simple:
SELECT COUNT(*)
FROM slk
This is a poor query. It selects all 55862 rows from the slk table and joins all 55862 rows to two other tables.
JOINs on large result sets are performance killers because MySQL must, at best, perform a seek for each row in the master table to the corresponding rows in the detail table. If there are too many rows, MySQL will decide it's just faster to scan the entire detail table rather than perform so many seeks.
Creating a multi-column index on node_users: (uid, type), as ypercube suggested, will help the second join (to the node_users) table.
Ideally, if this query were using INNER JOINs instead of LEFT OUTER JOINs, we could optimize the query by allowing MySQL to traverse it backwards, starting with the AND node_users.type = 'profile' and giving it the index that ypercube suggested, in the order he suggested. However, since they are left joins, MySQL will still want to get all rows in the slk table, and will start from there.
The only additional thing you can do to improve the performance of this query without modifying it is to avoid hitting the table data by using covering indexes.
This will use a lot more memory, but hopefully, it will be faster because it can read all the values from the indexes (in memory) rather than hitting the disk. This implies that you have enough RAM to support having all of the indexes in memory and you've configured MySQL to use it.
You already have a covering index on users (see Using index in the EXPLAIN result). You want all three lines of the DERIVED query to say Using index in the Extra column.
Create the additional following covering index:
slk: (key_id, uid)
This one was already mentioned above, but I'm including it here again so you don't forget it:
node_users: (uid, type)
You won't get breakthrough performance here because you're still having to do all of the JOINs, but you will get some improvement. Let us know how much faster it is. I'm guessing about twice as fast.

Slow MySQL Updates/Inserts/Deletes

I seem to be having slow inserts, updates and deletes on all tables on a specific database with MySQL. Not a lot of data in those tables (from 2k to 20k). Small number of columns (5-10), indexes (two of them), and no duplicate index issue. I'm running MySQL 5.0.45 with MyISAM.
I run the following query and it takes about 5-7 seconds:
UPDATE accounts SET updated_at = '2010-10-09 11:22:53' WHERE id = 8;
Selects seem to come back right away.
Explain gives me the following:
+----+-------------+----------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+-------+---------------+---------+---------+------+------+-------------+
| 1 | SIMPLE | accounts | index | NULL | PRIMARY | 4 | NULL | 1841 | Using index |
+----+-------------+----------+-------+---------------+---------+---------+------+------+-------------+
The profiler doesn't show any significant data for anything other than a seemingly high number of context switches:
+----------------------+----------+-------------------+---------------------+
| Status | Duration | Context_voluntary | Context_involuntary |
+----------------------+----------+-------------------+---------------------+
| (initialization) | 0.000057 | 0 | 0 |
| checking permissions | 0.000008 | 0 | 0 |
| Opening tables | 0.000013 | 0 | 0 |
| System lock | 0.000005 | 0 | 0 |
| Table lock | 0.000005 | 0 | 0 |
| init | 0.000061 | 0 | 0 |
| Updating | 0.000101 | 0 | 0 |
| end | 7.957233 | 7951 | 2 |
| query end | 0.000008 | 0 | 0 |
| freeing items | 0.000011 | 0 | 0 |
| closing tables | 0.000007 | 1 | 0 |
| logging slow query | 0.000002 | 0 | 0 |
+----------------------+----------+-------------------+---------------------+
This might also help:
+----------------------+----------+-----------------------+---------------+-------------+
| Status | Duration | Source_function | Source_file | Source_line |
+----------------------+----------+-----------------------+---------------+-------------+
| (initialization) | 0.000057 | check_access | sql_parse.cc | 5306 |
| checking permissions | 0.000008 | open_tables | sql_base.cc | 2629 |
| Opening tables | 0.000013 | mysql_lock_tables | lock.cc | 153 |
| System lock | 0.000005 | mysql_lock_tables | lock.cc | 162 |
| Table lock | 0.000005 | mysql_update | sql_update.cc | 167 |
| init | 0.000061 | mysql_update | sql_update.cc | 429 |
| Updating | 0.000101 | mysql_update | sql_update.cc | 560 |
| end | 7.957233 | mysql_execute_command | sql_parse.cc | 5122 |
| query end | 0.000008 | mysql_parse | sql_parse.cc | 6116 |
| freeing items | 0.000011 | dispatch_command | sql_parse.cc | 2146 |
| closing tables | 0.000007 | log_slow_statement | sql_parse.cc | 2204 |
| logging slow query | 0.000002 | dispatch_command | sql_parse.cc | 2169 |
+----------------------+----------+-----------------------+---------------+-------------+
Additional info:
It's running on a CentOS-5 VPS with 4 gigs of ram guaranteed. No index on the updated_at column and not triggers anywhere.
[New things that I tried]
Created a new table (using like)
running innodb and inserted all
records from one of the affected
tables. (same problem)
Backed up the database and restored it to a
different database within the same
server instance. (same problem)
Restored that same backup to my
local machine and I didn't have a
problem.
Tried another database
within the same mysql server
instance that has the problem
database and the other database (a
Wordpress DB) ran
updates/inserts/deletes just fine.
Restarted mysqld and restarted the entire server last night (same problem)
Updated MySQL to version 5.0.77 (same problem)
Deleted all indexes from one of the affected tables (same problem)
Any ideas what to look at next or what might be the issue? Seems to be more of a recent problem though I can't say when it started to show up exactly.
If you have variable length rows, you might need to run OPTIMIZE TABLE occasionally.
Finally found the answer. That database was somehow missing the MYD and MYI files and still running. Not sure how that's possible considering that the MYD file holds the data for MyISAM tables but that was causing the slow inserts/updates/deletes.
I ran an ALTER TABLE to set the engine to MyISAM (which it already was) and it recreated those files. Updates/inserts/deletes running fast again!