Slow query times on AWS RDS but not on DigitalOcean LAMP - mysql

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!

Related

SELECT query taking too long after MySQL upgrade

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

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.

query extremely slow after migration to mysql 5.7

I have a MySQL database with InnoDB tables summing up over 10 ten GB of data that I want to migrate from MySQL 5.5 to MySQL 5.7. And I have a query that looks a bit like:
SELECT dates.date, count(mySub2.myColumn1), sum(mySub2.myColumn2)
FROM (
SELECT date
FROM dates -- just a table containing all possible dates next 5 years
WHERE date BETWEEN '2016-06-01' AND '2016-09-03'
) AS dates
LEFT JOIN (
SELECT o.id, time_start, time_end
FROM order AS o
INNER JOIN order_items AS oi on oi.order_id = o.id
WHERE time_start BETWEEN '2016-06-01' AND '2016-09-03'
) AS mySub1 ON dates.date >= mySub1.time_start AND dates.date < mySub1.time_end
LEFT JOIN (
SELECT o.id, time_start, time_end
FROM order AS o
INNER JOIN order_items AS oi on oi.order_id = o.id
WHERE o.shop_id = 50 AND time_start BETWEEN '2016-06-01' AND '2016-09-03'
) AS mySub2 ON dates.date >= mySub2.time_start AND dates.date < mySub2.time_end
GROUP BY dates.date;
My problem is that this query is performing fast in MySQL 5.5 but extremely slow in MySQL 5.7.
In MySQL 5.5 it is taking over 1 second at first and < 0.001 seconds every recurring execution without restarting MySQL.
In MySQL 5.7 it is taking over 11.5 seconds at first and 1.4 seconds every recurring execution without restarting MySQL.
And the more LEFT JOINs I add to the query, the slower the query becomes in MySQL 5.7.
Both instances now run on the same machine, on the same hard drive and with the same my.ini settings. So it isn't hardware.
The execution plans do differ, though and I don't know what to make from it.
This is the EXPLAIN EXTENDED on MySQL 5.5:
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | extra |
|----|-------------|------------|-------|---------------|-------------|---------|-----------|-------|----------|---------------------------------|
| 1 | PRIMARY | dates | ALL | | | | | 95 | 100.00 | Using temporary; Using filesort |
| 1 | PRIMARY | <derived2> | ALL | | | | | 281 | 100.00 | '' |
| 1 | PRIMARY | <derived3> | ALL | | | | | 100 | 100.00 | '' |
| 3 | DERIVED | o | ref | xxxxxx | shop_id_fk | 4 | '' | 1736 | 100.00 | '' |
| 3 | DERIVED | oc | ref | xxxxx | order_id_fk | 4 | myDb.o.id | 1 | 100.00 | Using index |
| 2 | DERIVED | o | range | xxxx | date_start | 3 | | 17938 | 100.00 | Using where |
| 2 | DERIVED | oc | ref | xxx | order_id_fk | 4 | myDb.o.id | 1 | 100.00 | Using where |
This is the EXPLAIN EXTENDED on MySQL 5.7:
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | extra |
|----|-------------|-------|--------|---------------|-------------|---------|------------------|------|----------|----------------|
| 1 | SIMPLE | dates | ALL | | | | | 95 | 100.00 | Using filesort |
| 1 | SIMPLE | oi | ref | xxxxxx | order_id_fk | 4 | const | 228 | 100.00 | |
| 1 | SIMPLE | o | eq_ref | xxxxx | PRIMARY | 4 | myDb.oi.order_id | 1 | 100.00 | Using where |
| 1 | SIMPLE | o | ref | xxxx | shop_id_fk | 4 | const | 65 | 100.00 | Using where |
| 1 | SIMPLE | oi | ref | xxx | order_id_fk | 4 | myDb.o.id | 1 | 100.00 | Using where |
I want to understand why the MySQLs treat the same query that much different, and how I can tweak MySQL 5.7 to be faster?
I'm not looking for help on rewriting the query to be faster, as that is something I am already doing on my own.
As can be read in the comments, #wchiquito has suggested to look at the optimizer_switch. In here I found that the switch derived_merge could be set to off, to fix this new, and in this specific case undesired, behaviour.
set session optimizer_switch='derived_merge=off'; fixes the problem.
(This can also be done with set global ... or be put in the my.cnf / my.ini)
Building and maintaining a "Summary Table" would make this query run much faster than even 1 second.
Such a table would probably include shop_id, date, and some count.
More on summary tables.
I too faced slow query execution issue after migrating to mysql 5.7 and in my case, even setting session optimizer_switch to 'derived_merge=off'; didn't help.
Then, I followed this link: https://www.saotn.org/mysql-innodb-performance-improvement/ and the query's speed became normal.
To be specific my change was just setting these four parameters in my.ini as described in the link:
innodb_buffer_pool_size
innodb_buffer_pool_instances
innodb_write_io_threads
innodb_read_io_threads

mysql query taking too long to execute

I have a query that is taking way too long to execute (4 seconds) even though all the fields i am querying against are indexed. Below are the query and the explain results. Any ideas what the problem is? (mysql CPU usage shoots up to 100% when executing the query
EXPLAIN SELECT count(hd.did) as NumPo, `hd`.`sid`, `src`.`Name`
FROM (`hd`)
JOIN `result` ON `result`.`did` = `hd`.`did`
JOIN `sf` ON `sf`.`fid` = `hd`.`fid`
JOIN `src` ON `src`.`sid` = `hd`.`sid`
WHERE `sf`.`tid` = 2
AND `result`.`set` = 'xxxxxxx'
GROUP BY `hd`.`sid`
ORDER BY `NumPo` DESC
LIMIT 10;
+----+-------------+--------------+--------+-------------------------+---------+---------+--------------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------+--------+-------------------------+---------+---------+--------------------------+------+----------------------------------------------+
| 1 | SIMPLE | sf | ref | PRIMARY,type | type | 2 | const | 4 | Using index; Using temporary; Using filesort |
| 1 | SIMPLE | hd | ref | PRIMARY,sid,fid | FeedID | 4 | f2.sf.fid | 3 | |
| 1 | SIMPLE | result | ALL | resultset | NULL | NULL | NULL | 5322 | Using where; Using join buffer |
| 1 | SIMPLE | src | eq_ref | PRIMARY | PRIMARY | 4 | f2.hd.sid | 1 | |
+----+-------------+--------------+--------+-------------------------+---------+---------+--------------------------+------+----------------------------------------------+
| 1 | SIMPLE | result | ALL | resultset | NULL | NULL | NULL | 5322 | Using where; Using join buffer |
It looks like it's not using an index on the biggest table. I'm having trouble guessing what this query is supposed to do, but it looks like you have an index on result.set, so I'd try adding one to result.did and see if it helps.

How can a 'WHERE column LIKE "%expression%" ' perform better than a MATCH(column) AGAINST("expression") in MySQL?

I've run into a serious MySQL performance bottleneck which I'm unable to understand and resolve. Here are the table structures, indexes and record counts (bear with me, it's only two tables):
mysql> desc elggobjects_entity;
+-------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------------+------+-----+---------+-------+
| guid | bigint(20) unsigned | NO | PRI | NULL | |
| title | text | NO | MUL | NULL | |
| description | text | NO | | NULL | |
+-------------+---------------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
mysql> show index from elggobjects_entity;
+--------------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+--------------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| elggobjects_entity | 0 | PRIMARY | 1 | guid | A | 613637 | NULL | NULL | | BTREE | |
| elggobjects_entity | 1 | title | 1 | title | NULL | 131 | NULL | NULL | | FULLTEXT | |
| elggobjects_entity | 1 | title | 2 | description | NULL | 131 | NULL | NULL | | FULLTEXT | |
+--------------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
3 rows in set (0.00 sec)
mysql> select count(*) from elggobjects_entity;
+----------+
| count(*) |
+----------+
| 613637 |
+----------+
1 row in set (0.00 sec)
mysql> desc elggentity_relationships;
+--------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+---------------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| guid_one | bigint(20) unsigned | NO | MUL | NULL | |
| relationship | varchar(50) | NO | MUL | NULL | |
| guid_two | bigint(20) unsigned | NO | MUL | NULL | |
| time_created | int(11) | NO | | NULL | |
+--------------+---------------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
mysql> show index from elggentity_relationships;
+--------------------------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+--------------------------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+
| elggentity_relationships | 0 | PRIMARY | 1 | id | A | 11408236 | NULL | NULL | | BTREE | |
| elggentity_relationships | 0 | guid_one | 1 | guid_one | A | NULL | NULL | NULL | | BTREE | |
| elggentity_relationships | 0 | guid_one | 2 | relationship | A | NULL | NULL | NULL | | BTREE | |
| elggentity_relationships | 0 | guid_one | 3 | guid_two | A | 11408236 | NULL | NULL | | BTREE | |
| elggentity_relationships | 1 | relationship | 1 | relationship | A | 11408236 | NULL | NULL | | BTREE | |
| elggentity_relationships | 1 | guid_two | 1 | guid_two | A | 11408236 | NULL | NULL | | BTREE | |
+--------------------------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+
6 rows in set (0.00 sec)
mysql> select count(*) from elggentity_relationships;
+----------+
| count(*) |
+----------+
| 11408236 |
+----------+
1 row in set (0.00 sec)
Now I'd like to use an INNER JOIN on those two tables and perform a full text search.
Query:
SELECT
count(DISTINCT o.guid) as total
FROM
elggobjects_entity o
INNER JOIN
elggentity_relationships r on (r.relationship="image" AND r.guid_one = o.guid)
WHERE
((MATCH (o.title, o.description) AGAINST ('scelerisque' )))
This gave me a 6 minute (!) response time.
On the other hand this one
SELECT
count(DISTINCT o.guid) as total
FROM
elggobjects_entity o
INNER JOIN
elggentity_relationships r on (r.relationship="image" AND r.guid_one = o.guid)
WHERE
((o.title like "%scelerisque%") OR (o.description like "%scelerisque%"))
returned the same count value in 0.02 seconds.
How is that possible? What am I missing here?
(MySQL info: mysql Ver 14.14 Distrib 5.1.49, for debian-linux-gnu (x86_64) using readline 6.1)
EDIT
EXPLAINing the first query (using match .. against) gives:
+----+-------------+-------+----------+-----------------------+--------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+----------+-----------------------+--------------+---------+-------+------+-------------+
| 1 | SIMPLE | r | ref | guid_one,relationship | relationship | 152 | const | 6145 | Using where |
| 1 | SIMPLE | o | fulltext | PRIMARY,title | title | 0 | | 1 | Using where |
+----+-------------+-------+----------+-----------------------+--------------+---------+-------+------+-------------+
while the second query (using LIKE "%..%"):
+----+-------------+-------+--------+-----------------------+--------------+---------+---------------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-----------------------+--------------+---------+---------------------+------+-------------+
| 1 | SIMPLE | r | ref | guid_one,relationship | relationship | 152 | const | 6145 | Using where |
| 1 | SIMPLE | o | eq_ref | PRIMARY | PRIMARY | 8 | elgg1710.r.guid_one | 1 | Using where |
+----+-------------+-------+--------+-----------------------+--------------+---------+---------------------+------+-------------+
By combining your experience and EXPLAIN's results, it seems that fulltext index is not as useful as you expect in this particular case. This depends on particular data in your database, on database structure or/and particular query.
Usually database engines use no more than one index per table. So when the table has more than one index, query optimizer tries to use the better one. But optimizer is not always clever enough.
EXPLAIN's output shows that database query optimizer decided to use indexes for relationship and title. The relationship filter reduces table elggentity_relationships to 6145 rows. And the title filter reduces the table elggobjects_entity to 72697 rows. Then MySQL needs to join those tables (6145 x 72697 = 446723065 filtering operations) without using any index because indexes have already been used for filtering. In this case this can be too much. MySQL can even make a decision to keep intermediate calculations in the hard drive by trying to keep enough free space in memory.
Now let's take a look into another query. It uses relationship and PRIMARY KEY (of table elggobjects_entity) as its indexes. The relationship filter reduces table elggentity_relationships to 6145 rows. By joining those tables on PRIMARY KEY index, the result gets only 3957 rows. This is not much for the last filter (i.e. LIKE "%scelerisque%"), even if index is NOT used for this purpose at all.
As you can see the speed much depends on indexes selected for a query. So, in this particular case the PRIMARY KEY index is much more useful than fulltext title index, because PRIMARY KEY has bigger impact for result reduction than title.
MySQL is not always clever to set the right indexes. We can do this manually, by using clauses like IGNORE INDEX (index_name), FORCE INDEX (index_name), etc.
But in your case the problem is that if we use MATCH() AGAINST() in a query then the fulltext index is required, because MATCH() AGAINST() doesn't work without fulltext index at all. So this is the main reason why MySQL has chosen incorrect indexes for the query.
UPDATE
OK, I did some investigation.
Firstly, you may try to force MySQL to use guid_one index instead of relationship on table elggentity_relationships: USE INDEX (guid_one).
But for even better performance I think you can try to create one index for the composition of two columns (guid_one, membership). Current index guid_one is very similar, but for 3 columns, not for 2. In this query there are only 2 columns used. In my opinion after index creation MySQL should automatically use the right index. If not, force MySQL to use it.
Note: After index creation don't forget to remove old USE INDEX instruction from your query, because this may prevent query from using the newly created index. :)