MySQL very long queries - mysql

I have an quite large db (800+Mb dump file) that I imported to my local server. Its a Wordpress db from witch i need to extract certain posts. There is around 160000 posts inside.
Currently im testing a bit with MySql Workbench running simple queries with JOIN and it requires a lot of time, so long actually that Workbench stops processing.
Here`s an example:
SELECT
COUNT(*)
FROM wp_posts
LEFT JOIN wp_term_relationships
ON wp_posts.ID = wp_term_relationships.object_id
LEFT JOIN wp_term_taxonomy
ON wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id
LEFT JOIN wp_terms
ON wp_term_taxonomy.term_id = wp_terms.term_id
WHERE wp_terms.term_id = 195;
Running over 600 seconds.
Here is an wordpress db schema:
Of course chance is I'm just bad at SQL, not really my field...

If you have all indexes on columns you use for joining (wp_posts.ID, wp_term_relationships.object_id etc.), this should not be a problem, and query should be executed in less than 1 sec (1 sec is a lot, too).
Also, there might be waiting on other queries in queue (locks), so you should add this to those queries:
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;
SELECT
COUNT(*)
FROM
wp_posts
LEFT JOIN
wp_term_relationships ON wp_posts.ID = wp_term_relationships.object_id
LEFT JOIN
wp_term_taxonomy ON wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id
LEFT JOIN
wp_terms ON wp_term_taxonomy.term_id = wp_terms.term_id
WHERE
wp_terms.term_id = 195;
COMMIT ;
Create indexes in workbench. I can see here that you are joining on IDs on every table, so because those are ID columns, they should be PRIMARY KEY, and create UNIQUE Clustered index on them.

If you are really just running a count you can get your result with:
SELECT COUNT(*)
FROM wp_term_relationships wtr
JOIN wp_term_taxonomy wtt
ON wtt.term_taxonomy_id = wtr.term_taxonomy_id
WHERE wtt.term_id = 195;
You don't need the information from the obligatory wp_terms or wp_posts records that are attached to these records.
You also don't need a LEFT JOIN as you are discarding NULL tuples with your WHERE condition.
As for the speed, I would suggest running the query prepended with EXPLAIN and checking that everything is indexed correctly and these indices are being used.

Related

Is there a faster way to select records from a table and query its sub tables

He everyone,
I would like to get all records from a table that are changed, but also if one of its child tables has changed.
I have a working query that does this using subqueries but it takes very long (2 minutes) to complete.
Is there any other way to accomplish this that runs faster?
Thanks!
Wouter
SELECT
wp_posts.id AS order_id,
br_order_archive.id AS archive_id,
wp_posts.post_date_gmt AS date,
wp_posts.post_modified_gmt AS lastmod
FROM
wp_posts
LEFT JOIN
br_order_archive ON br_order_archive.order_id = wp_posts.id
WHERE
wp_posts.post_type = "shop_order"
AND
wp_posts.post_status = "wc-completed"
AND (
br_order_archive.order_id IS NULL
OR wp_posts.post_modified_gmt != br_order_archive.lastmod
OR br_order_archive.lastmod_licenses != (
select max(wp_woocommerce_software_licenses.created)
from wp_woocommerce_software_licenses
where wp_posts.id = wp_woocommerce_software_licenses.order_id
)
OR br_order_archive.lastmod_activations != (
select max(wp_woocommerce_software_activations.activation_time)
from wp_woocommerce_software_activations
LEFT JOIN wp_woocommerce_software_licenses ON wp_woocommerce_software_activations.key_id = wp_woocommerce_software_licenses.key_id
where wp_posts.id = wp_woocommerce_software_licenses.order_id
)
)
ORDER BY
wp_posts.ID desc
In the absence of the necessary debugging information, let's start with this bit....
select max(a.activation_time)
from wp_woocommerce_software_activations a
LEFT
JOIN wp_woocommerce_software_licenses l
ON a.key_id = l.key_id
where p.id = l.order_id
A LEFT JOIN on a table from which you select no columns is a strange thing, as is the correlation between the LEFT JOINed table and the posts table (p). Normally, a LEFT JOINed table would not have an equals operator in a WHERE clause. For my own sanity, I would start by rewriting this as an uncorrelated subquery, regardless of the impact on performance.

very slow query with ORDER BY

I have read through many tutorials online and here on stackoverflow but I still can't figure out how to solve the problem I'm facing right now.
I would like to tell you guys that I'm a mysql newbie so please forgive my noobness.
Alright, the query is this and it grabs the information that I need from wordpress database
SELECT
product.ID productId,
product.guid productLink,
product.post_title productTitle,
post.ID postId,
post.post_title postTitle,
post.post_content postContent,
post.post_date postDate,
tm.slug typeSlug, tm.name typeName,
tm2.slug langSlug, tm2.name langName,
tm3.slug pubSlug, tm3.name pubName,
IFNULL(wl.id,0) wishlist
FROM wp_posts product
JOIN wp_postmeta meta ON meta.meta_key = 'p2m' AND meta.meta_value=product.ID
JOIN wp_posts post ON post.ID = meta.post_id
JOIN wp_term_relationships tr ON tr.object_id = product.ID
JOIN wp_term_taxonomy tt ON tt.term_taxonomy_id = tr.term_taxonomy_id AND tt.taxonomy = 'mtype'
JOIN wp_terms tm ON tm.term_id = tt.term_id
JOIN wp_term_relationships tr2 ON tr2.object_id = product.ID
JOIN wp_term_taxonomy tt2 ON tt2.term_taxonomy_id = tr2.term_taxonomy_id AND tt2.taxonomy = 'language'
JOIN wp_terms tm2 ON tm2.term_id = tt2.term_id
JOIN wp_term_relationships tr3 ON tr3.object_id = product.ID
JOIN wp_term_taxonomy tt3 ON tt3.term_taxonomy_id = tr3.term_taxonomy_id AND tt3.taxonomy = 'publisher'
JOIN wp_terms tm3 ON tm3.term_id = tt3.term_id
LEFT JOIN wp_yith_wcwl wl ON wl.user_id = 1 AND wl.prod_id = product.ID AND wl.post_id = post.ID
WHERE product.post_type = 'product'
ORDER BY post.post_date DESC LIMIT 0,35
When I remove "ORDER BY post.post_date DESC" the speed of the query gets down to .03 seconds which is freaking amazing.. But with the addition of the "ORDER BY post.post_date DESC" the speed of the query goes to amazing 10+ seconds which is way too long..
I've used EXPLAIN and it seems that there is usage of filesort when the ORDER BY by date gets into the query.
I need to have my query reply back the results according to the post_date so I can't figure out what I could do at this point...
Additionally, I would like to point it out that in Database Description of wordpress there is an INDEX referred as "type_status_date" which could be used in my case. However, I'm totally clueless where to use it and how to do it. If there is anyone who can point out the flaw in the logic of my query or help me out with the optimization of the query (or index) please do so. Thanks for you kind attention!
P.S: I don't know how to create an index too :)
Initial Result of EXPLAIN with ORDER BY
JOIN wp_postmeta meta
ON meta.meta_key = 'p2m' -- filters
AND meta.meta_value=product.ID -- shows relation
is confusing. JOIN...ON is used to say how two tables are related. Filters belong in WHERE:
WHERE ...
AND meta.meta_key = 'p2m'
...
wp_postmeta is not well indexed. More discussion here .
Adding INDEX(post_date) may or may not help performance -- It depends on how quickly 35 good rows are found.
From the EXPLAIN, we see that the worst part is getting into meta -- something like 30K rows to look through. This _estimates that there are 30 rows with meta_key = 'p2m'. How many rows are there?
Unfortunately wp_postmeta is not designed to efficiently start with the meta_key+meta_value. This is a general problem with key-value stores (such as Posts in WP), especially when the 'value' is LONGTEXT.
The index on wp_post for type_status_date, has the date field as the third field of the index,
type_status_date INDEX
post_type
post_status
post_date
ID
So you have a predicate for post type, but post status is not included in your query in any predicate, at best it can therefore do a partial index scan of the index (sometimes called a skip scan or range scan depending on the db, my sql is not going to play ball easily on that) but it will be slower.
That is a best case scenario though, with all those joins and additional fields not covered by the index the cost of the index scan and row lookups could be far too high to consider even touching the index vs a straight scan.
It would help if you post the explain plan, it would help confirm what the optimizer was doing. The above is a more generic DB engine commentary.
type_status_date is a combined index so it's used only if you order by all it's components. It cannot be used by MySQL to order by only post_date. So the best solution is to add an index by post_date.

Why is MYSQL slow_query_log not enabled?

I have the following in .my.cnf
# LOGGING #
slow_query_log = ON
slow_query_log_file = /var/log/mariadb/slow_query.log
log-queries-not-using-indexes = 1
When I run tuning-primer.sh I get this:
SLOW QUERIES
The slow query log is NOT enabled.
Current long_query_time = 10.000000 sec.
You have 0 out of 36 that take longer than 10.000000 sec. to complete
Your long_query_time seems to be fine
Can someone explain how is this possible?
Apparently the slowlog is working now. Do you know what fixed that issue?
Meanwhile, this has morphed into query tuning...
What is #1 for? Why is it run so often? It returns an average of 156K rows examined (the whole table?), but only 665 rows returned. 665 is a lot of rows; do you really need them all? Could more filtering be done in the SQL?
It sounds like there is no INDEX(autoload) -- add it; it should speed up the query considerably.
#1
SELECT option_name, option_value
FROM wp_options
WHERE autoload = 'S'
What are you doing with the thousands of rows from the following? And you are preforming them thousands of times?
#2
SELECT st.value AS tra, s.value AS org, s.domain_name_context_md5 AS ctx
FROM wp_icl_strings s
LEFT JOIN wp_icl_string_translations st ON s.id=st.string_id
AND st.status=N
AND st.language='S'
AND s.language!='S'
#3
SELECT slug, taxonomy
FROM wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_term_taxonomy ON (wp_term_relationships.term_taxonomy_id =
wp_term_taxonomy.term_taxonomy_id )
INNER JOIN wp_terms ON (wp_term_taxonomy.term_id = wp_terms.term_id )
WHERE wp_posts.ID IN ("S","S","S","S","S","S","S","S","S",...)
ORDER BY wp_terms.name ASC
#4
SELECT t.element_id, tax.term_id, tax.taxonomy
FROM wp_icl_translations t
JOIN wp_term_taxonomy tax ON t.element_id = tax.term_taxonomy_id
AND t.element_type = CONCAT('S', tax.taxonomy)
JOIN wp_terms terms ON terms.term_id = tax.term_id
WHERE tax.term_id != tax.term_taxonomy_id
Why the LEFT in #2? That probably prevents starting with st, which might be more selective with INDEX(language, status).
In #3: wp_terms might benefit from INDEX(name).
In #4: The schema design led to the clumsy CONCAT('S', tax.taxonomy); can that be rectified? That is, can t.element_type and tax.taxonomy look the same -- either both with the prefix or both without? Or maybe the prefix is a separate column?
If you would like to discuss any of these further, please provide SHOW CREATE TABLE and EXPLAIN SELECT ....

mysql slow queries and timeout in wordpress

I am not an expert in sql.
My wordpress started to return timeouts and respond really slow.
when I started digging, I noticed that the slow_query log has a lot to tell me.
unfortunately I have a lot of slow queries.
for example:
# Time: 140425 17:03:29
# User#Host: geektime[geektime] # localhost []
# Query_time: 7.024031 Lock_time: 0.000432 Rows_sent: 0 Rows_examined: 0
SET timestamp=1398434609;
SELECT wp_posts.*
FROM wp_posts
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)
LEFT JOIN wp_postmeta AS order1 ON order1.post_id = wp_posts.ID
AND order1.meta_key = '_event_start_date'
LEFT JOIN wp_postmeta AS order2 ON order2.post_id = wp_posts.ID
AND order2.meta_key = '_event_start_time'
WHERE 1=1
AND wp_posts.post_type = 'event'
AND (wp_posts.post_status = 'publish'
OR wp_posts.post_status = 'future'
OR wp_posts.post_status = 'draft'
OR wp_posts.post_status = 'pending')
AND ((wp_postmeta.meta_key = '_event_start_date'
AND CAST(wp_postmeta.meta_value AS CHAR) BETWEEN '2014-04-11' AND '2014-04-17')
OR (mt1.meta_key = '_event_end_date'
AND CAST(mt1.meta_value AS CHAR) BETWEEN '2014-04-11' AND '2014-04-17'))
GROUP BY wp_posts.ID
ORDER BY order1.meta_value,
order2.meta_value ASC;
The columns post_id, meta_id and meta_key are indexed in wp_postmeta table.
The columns ID, post_name, post_type, post_status, post_date,post_parent, post_author and guid are indexed in wp_posts table.
however, the columns ID and GUID are indexed twice, is it bad?
and there are 4 indexs with the same key_name: type_status_date, is it bad?
How could it be that I have 60K rows in wp_posts and 3M rows in wp_postmeta?
I know its a lot to ask but I really tried to understand from researching online.
thanks in advance.
however, the columns ID and GUID are indexed twice, is it bad?
There are two different columns, so no, unless you're meaning that both have two indexes on them — in which case yes, it's bad and likely a bug in one of your theme or plugins (or a prior bug in WP itself).
and there are 4 indexs with the same key_name: type_status_date, is it bad?
Same as above: if you mean four identical indexes, it's either a theme or plugin or WP bug and you can safely drop the duplications.
How could it be that I have 60K rows in wp_posts and 3M rows in wp_postmeta?
Because the WP meta API sucks and enforces a database anti-pattern called the Entity Attribute Value (also known as EAV):
http://en.wikipedia.org/wiki/Entity-attribute-value_model
Cursory googling SO will yield plenty of threads that explain why it is a bad idea to store data in an EAV or equivalent (json, hstore, xml, whatever) if the stuff ever needs to appear in e.g. a where, join or order by clause.
You can see the inefficiencies first-hand in form of the slow query you highlighted. The query is joining the meta table four times, does so twice with a cast operator to boot — and it casts the value to char instead of date at that. Adding insult to injury, it then proceeds to order rows using values stored within it. It is a recipe for poor performance.
There is, sadly, little means of escaping the repulsive stench of this sewage, short of writing your own plugins that create proper tables to store, index and query the data you need in lieu of using the WP meta API, its wretched quoting madness, and the putrid SQL that results from using it.
One thing that you can do as temporary duct tape and WD-40 measure while you rewrite the plugins you're using from the ground up, is to toss callbacks on one or more of the filters you'll find in the giant mess of a class method that is WP_Query#get_posts(). For instance the posts_request filter, which holds the full and final SQL query, allows you to rewrite anything to your liking using regex-foo. It's no magic bullet: doing so will allow you to fix bugs such as integer values getting sorted lexicographically and such, as well as toss in very occasional query optimizations; little more.
Edit: Upon re-reading your query, methinks you're mostly in luck with respect to that last point. Your particular query features the following abomination:
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)
LEFT JOIN wp_postmeta AS order1 ON order1.post_id = wp_posts.ID
AND order1.meta_key = '_event_start_date'
LEFT JOIN wp_postmeta AS order2 ON order2.post_id = wp_posts.ID
AND order2.meta_key = '_event_start_time'
Two of those have _event_start_date in common, so you can factor it out:
SELECT wp_posts.*
FROM wp_posts
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
AND wp_postmeta.meta_key = '_event_start_date'
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)
AND mt1.meta_key = '_event_end_date'
INNER JOIN wp_postmeta AS order2 ON order2.post_id = wp_posts.ID
AND order2.meta_key = '_event_start_time'
WHERE 1=1
AND wp_posts.post_type = 'event'
AND (wp_posts.post_status = 'publish'
OR wp_posts.post_status = 'future'
OR wp_posts.post_status = 'draft'
OR wp_posts.post_status = 'pending')
AND (CAST(wp_postmeta.meta_value AS CHAR) BETWEEN '2014-04-11' AND '2014-04-17'
OR CAST(mt1.meta_value AS CHAR) BETWEEN '2014-04-11' AND '2014-04-17')
GROUP BY wp_posts.ID
ORDER BY wp_postmeta.meta_value,
order2.meta_value ASC;
Among other things, slow performance is caused by the use of functions like this:
AND CAST(wp_postmeta.meta_value AS CHAR) BETWEEN '2014-04-11' AND '2014-04-17')
Assuming that field is a date field, you will get better performance with something like this:
and wp_postmeta.meta_value >= AStartDateVariable
and wp_postmeta.meta_value < TheDayAfterAnEndDateVariable
That will be even more true if meta_value is indexed. I assume you will be sending these variables as query parmameters.
Holy cow! 3 megarows in postmeta? 60k posts? Something is seriously wrong with your installation.
Is it possible that your events table is open to spammers entering rubbish?
Do you have tons of old expired events that could somehow be purged from your system?
You may be able to get your system back on the air by increasing your timeout value. If you know how to handle php.ini, go find the timeout value and increase it, or ask your hosting company for help.
Are you on one of those $5 per month hosting companies? With sixty thousand events to handle, you may need to upgrade.
The proximate cause of the timeout is obvious. This sequence of code is full-scanning that monster post_meta table TWICE!
Why? It has an OR in it. And it is applying functions to the value of a column.
AND ((wp_postmeta.meta_key = '_event_start_date'
AND CAST(wp_postmeta.meta_value AS CHAR) BETWEEN '2014-04-11' AND '2014-04-17')
OR (mt1.meta_key = '_event_end_date'
AND CAST(mt1.meta_value AS CHAR) BETWEEN '2014-04-11' AND '2014-04-17'))
One of the disadvantages of the WordPress schema when you scale up a site is the generic nature of the postmeta table. This query does date range searches, but it's hard to index a key-value repository like postmeta to optimize those.
Do you know your way around the code of the Events Manager plugin you're using? If so, you may want to investigate optimizing this yourself.
If not, seek support from the Events Manager plugin developer.

What does "using join buffer" means in the Explain table of an MySQL query?

I have the following complex query and I notice that it is making my website so slow I want to find a way to optimize it:
SELECT tahminler.result,
tahminler.tahmin,
tahminler.match_id,
tahminler.timestamp,
tahminler.tahmin_text,
users.username,
matches_of_comments.tournament_id,
matches_of_comments.match_status,
matches_of_comments.match_date,
matches_of_comments.localteam_name,
matches_of_comments.visitorteam_name,
matches_of_comments.localteam_id,
matches_of_comments.visitorteam_id,
matches_of_comments.localteam_goals,
matches_of_comments.visitorteam_goals,
new_iddaa.iddaa_code,
tahminler_results.ms1,
tahminler_results.ms2,
tahminler_results.ms0,
tahminler_results.alt,
tahminler_results.ust,
tahminler_results.tg_0_1,
tahminler_results.tg_2_3,
tahminler_results.tg_4_6,
tahminler_results.tg_7,
tahminler_results.kg_var,
tahminler_results.kg_yok,
tahmins.tahmin as text_tahmin
FROM tahminler
INNER JOIN users on users.id = tahminler.user_id
INNER JOIN matches_of_comments on tahminler.match_id = matches_of_comments.match_id
Left JOIN new_iddaa on new_iddaa.match_id = matches_of_comments.match_id
INNER JOIN tahmins on tahminler.tahmin = tahmins.id
LEFT JOIN tahminler_results on tahminler.match_id = tahminler_results.match_id
Where tahminler.user_id = $user_id
order by tahminler.timestamp DESC
I do not have much experience in databases or optimization so I did an Explain for this query and i got this table :
I think the problem in the row which tells "using join buffer" but what does that mean ??
can you help me to understand this point and making the query optimized ?
I'd recommend checking for indices, especially on the columns you want to join on. Do you have an index on matches_of_comments.match_id? Also, an index on tahmins.id seems to be missing.