optimize the mysql query - mysql

I have following mysql query which is taking long time(40s) to load the results.
SELECT SQL_CALC_FOUND_ROWS blog_posts.ID FROM blog_posts
LEFT JOIN blog_term_relationships AS tt0 ON (blog_posts.ID = tt0.object_id)
LEFT JOIN blog_term_relationships AS tt1 ON (blog_posts.ID = tt1.object_id)
LEFT JOIN blog_term_relationships AS tt2 ON (blog_posts.ID = tt2.object_id)
LEFT JOIN blog_term_relationships AS tt3 ON (blog_posts.ID = tt3.object_id)
WHERE 1=1
AND ( ( tt0.term_taxonomy_id IN (141,177) AND tt1.term_taxonomy_id IN (2389,2390) )
OR ( tt2.term_taxonomy_id IN (167,1169,1715) AND tt3.term_taxonomy_id IN (2519,2520) ) )
AND blog_posts.post_type = 'post' AND (blog_posts.post_status = 'publish')
GROUP BY blog_posts.ID ORDER BY blog_posts.post_date ASC LIMIT 0, 20
Is there any way to optimize this query.
Edit:
This is related to wordpress and this query was automatically create from the wp_query.
Table structures as bellow,
blog_posts table:
CREATE TABLE `blog_posts` (
`ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`post_author` bigint(20) unsigned NOT NULL DEFAULT '0',
`post_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`post_date_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`post_content` longtext NOT NULL,
`post_title` text NOT NULL,
`post_excerpt` text NOT NULL,
`post_status` varchar(20) NOT NULL DEFAULT 'publish',
`comment_status` varchar(20) NOT NULL DEFAULT 'open',
`ping_status` varchar(20) NOT NULL DEFAULT 'open',
`post_password` varchar(255) NOT NULL DEFAULT '',
`post_name` varchar(200) NOT NULL DEFAULT '',
`to_ping` text NOT NULL,
`pinged` text NOT NULL,
`post_modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`post_modified_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`post_content_filtered` longtext NOT NULL,
`post_parent` bigint(20) unsigned NOT NULL DEFAULT '0',
`guid` varchar(255) NOT NULL DEFAULT '',
`menu_order` int(11) NOT NULL DEFAULT '0',
`post_type` varchar(20) NOT NULL DEFAULT 'post',
`post_mime_type` varchar(100) NOT NULL DEFAULT '',
`comment_count` bigint(20) NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`),
KEY `type_status_date` (`post_type`,`post_status`,`post_date`,`ID`),
KEY `post_parent` (`post_parent`),
KEY `post_author` (`post_author`),
KEY `post_name` (`post_name`(191))
) ENGINE=MyISAM AUTO_INCREMENT=125636 DEFAULT CHARSET=utf8
blog_term_relationships table:
CREATE TABLE `blog_term_relationships` (
`object_id` bigint(20) unsigned NOT NULL DEFAULT '0',
`term_taxonomy_id` bigint(20) unsigned NOT NULL DEFAULT '0',
`term_order` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`object_id`,`term_taxonomy_id`),
KEY `term_taxonomy_id` (`term_taxonomy_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
EXPLAIN QUERY:
enter image description here

Reformulate
SELECT SQL_CALC_FOUND_ROWS blog_posts.ID
FROM (
(
SELECT object_id
FROM blog_term_relationships AS tt0
JOIN blog_term_relationships AS tt1 USING(object_id)
WHERE tt0.term_taxonomy_id IN (141,177)
AND tt1.term_taxonomy_id IN (2389,2390)
)
UNION DISTINCT
(
SELECT object_id
FROM blog_term_relationships AS tt2
JOIN blog_term_relationships AS tt3 USING(object_id)
WHERE tt2.term_taxonomy_id IN (167,1169,1715)
AND tt3.term_taxonomy_id IN (2519,2520) )
) AS tt
JOIN blog_posts ON blog_posts.ID = tt.object_id
WHERE blog_posts.post_type = 'post'
AND blog_posts.post_status = 'publish'
ORDER BY blog_posts.post_date ASC
LIMIT 0, 20
This gets rid of the GROUP BY and does several other things to speed up the query.
Prefix index
`post_name` varchar(200) NOT NULL DEFAULT '',
KEY `post_name` (`post_name`(191))
) ENGINE=MyISAM AUTO_INCREMENT=125636 DEFAULT CHARSET=utf8
Make up your mind -- 191 is for version 5.6 with utf8mb4 (which you have not specified); 191 is so close to 200, you may as well make it VARCHAR(191). Getting rid of the prefix index is likely to speed up some of your queries.
InnoDB
Don't use MyISAM, move to InnoDB. That is for performance, robustness, etc. That will coincidentally fix an inefficiency in KEY term_taxonomy_id).
SQL_CALC_FOUND_ROWS
SQL_CALC_FOUND_ROWS is costly. It's purpose is passe.

Related

MySql unexpected query result

I have such a tables offers and offer_operating_systems related by offer_id. I made two queris and from my understanding they should return same result, but they don't
Query 1:
select
count(*)
from
`offers`
where
(
select count(*)
from `offer_operating_systems`
where
`offer_operating_systems`.`offer_id` = `offers`.`id`
and
`operating_system` = 'android'
) = 1
order by `id` asc
Query 2:
select
count(*)
from offer_operating_systems
where
operating_system = 'android'
order by `id` asc
Can someone explain to me why the results are not the same? Thanks!
EDITED
operating_systemcolumn is unique so each offer can have only one record with adnroid
Table structures
CREATE TABLE `offers` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`type` int(11) NOT NULL DEFAULT '0',
`url` text COLLATE utf8_unicode_ci,
`status` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'pending',
`api_created_at` timestamp NULL DEFAULT NULL,
`api_updated_at` timestamp NULL DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
KEY `offers_status_index` (`status`)
) ENGINE=InnoDB AUTO_INCREMENT=423 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
CREATE TABLE `offer_operating_systems` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`offer_id` int(10) unsigned NOT NULL,
`operating_system` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
UNIQUE KEY `offer_operating_systems_offer_id_operating_system_unique` (`offer_id`,`operating_system`),
KEY `offer_operating_systems_offer_id_foreign` (`offer_id`),
CONSTRAINT `offer_operating_systems_offer_id_foreign` FOREIGN KEY (`offer_id`) REFERENCES `offers` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=728 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

DATE_ADD in a subquery slows down execution

Good day.
Why date modification in a subquery reduces performance?
This request is fast (0.015 sec):
SELECT p.id, p.name, s.value
FROM points p
LEFT JOIN settings s ON p.id = s.point_id AND s.type_id = 1
WHERE p.parent_id = 1310
AND NOT EXISTS (SELECT 1 FROM events e WHERE e.point_id = p.id AND e.start_at > '2019-09-09 20:00:00')
UPD Explain:
'1', 'PRIMARY', 'p', 'ref', 'idx_parent_id_type', 'idx_parent_id_type', '5', 'const', '29', 'Using where'
'1', 'PRIMARY', 's', 'ref', 'p_id_idx,sid_idx', 'p_id_idx', '4', 'rm_api.p.id', '1', 'Using where'
'2', 'MATERIALIZED', 'e', 'range', 'idx_start_at_end_at,point', 'idx_start_at_end_at', '5', NULL, '3855', 'Using index condition'
This request is slow (~ 18 sec):
SELECT p.id, p.name, s.value
FROM points p
LEFT JOIN settings s ON p.id = s.point_id AND s.type_id = 1
WHERE p.parent_id = 1310
AND NOT EXISTS (SELECT 1 FROM events e WHERE e.point_id = p.id AND e.start_at > DATE_ADD('2019-09-09 20:00:00', INTERVAL COALESCE(s.value, 0) MINUTE))
UPD Explain:
1 PRIMARY p ref idx_parent_id_type idx_parent_id_type 5 const 29
1 PRIMARY s ref p_id_idx,sid_idx p_id_idx 4 rm_api.p.id 1 Using where
2 DEPENDENT SUBQUERY e ref idx_start_at_end_at,point point 4 rm_api.p.id 478 Using index condition; Using where
What can be done?
I doubt that I am using s.value correctly in the subquery
p.s. this request is also fast:
SELECT p.id, p.name, s.value
FROM points p
LEFT JOIN settins s ON p.id = s.point_id AND s.type_id = 1
WHERE p.parent_id = 1310
AND NOT EXISTS (SELECT 1 FROM events e WHERE e.point_id = p.id AND e.start_at > DATE_ADD('2019-09-09 20:00:00', INTERVAL 15 MINUTE))
UPD
Table points:
CREATE TABLE `points` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(160) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'Не указано',
`parent_id` int(10) unsigned DEFAULT 1,
`type` int(11) NOT NULL DEFAULT 0,
`status` int(11) NOT NULL DEFAULT 1,
`created_at` timestamp NOT NULL DEFAULT '1970-12-31 09:00:00',
`updated_at` timestamp NOT NULL DEFAULT '1970-12-31 09:00:00',
`capacity` int(11) NOT NULL DEFAULT 0,
`is_building` int(11) DEFAULT 0,
`is_ews_linked` int(11) NOT NULL DEFAULT 0,
`ews_resource_name` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`map_name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`other` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`human_name` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`booking_max_duration` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_parent_id_type` (`parent_id`,`type`)
) ENGINE=InnoDB AUTO_INCREMENT=2958 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Table settings:
CREATE TABLE `points_settins_types_storage` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`point_id` int(11) unsigned NOT NULL,
`settings_prop_type_id` int(11) unsigned NOT NULL,
`value` varchar(255) CHARACTER SET utf8 NOT NULL DEFAULT '',
PRIMARY KEY (`id`,`settings_prop_type_id`,`point_id`),
KEY `p_id_idx` (`point_id`),
KEY `sid_idx` (`settings_prop_type_id`),
CONSTRAINT `pid` FOREIGN KEY (`point_id`) REFERENCES `points` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `sid` FOREIGN KEY (`settings_prop_type_id`) REFERENCES `points_settings_types` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1062 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Table events:
CREATE TABLE `events` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(500) COLLATE utf8mb4_unicode_ci NOT NULL,
`start_at` datetime NOT NULL,
`end_at` datetime NOT NULL,
`point_id` int(11) NOT NULL,
`status` int(11) NOT NULL DEFAULT 0,
`owner_id` int(11) NOT NULL,
`approver_id` int(11) DEFAULT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
`date` datetime NOT NULL,
`approver_message` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`user_message` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`linked_vks_id` int(11) DEFAULT NULL,
`ews_event_id` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`is_from_exchange` int(11) NOT NULL DEFAULT 0,
`ews_event_change_key` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`content` varchar(10000) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`),
KEY `owner_id_k` (`owner_id`),
KEY `idx_start_at_end_at` (`start_at`,`end_at`),
KEY `end_start` (`end_at`,`start_at`) USING BTREE,
KEY `date` (`date`) USING BTREE,
KEY `status` (`status`) USING BTREE,
KEY `point` (`point_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2338492 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
For your query, start with in index on events(point_id, start_at). Perhaps that will help.
Probably not.
If the interval values are always positive, then try this redundant version (with the above index):
WHERE p.parent_id = 1310 AND
NOT EXISTS (SELECT 1
FROM events e
WHERE e.point_id = p.id AND
e.start_at > '2019-09-09 20:00:00' AND
e.start_at > DATE_ADD('2019-09-09 20:00:00', INTERVAL COALESCE(s.value, 0) MINUTE)
)
Yes, this looks silly. But the additional condition should make it easier to MySQL to use the index correctly.

mysql Query optimization task

Mentioned below is the query and the tables its is being run on ...
SELECT * FROM
tfl_acquistions a,
tfl_property_attributes b WHERE
a.id = b.property_id AND
attribute_id ='111' AND
a.id ='53a8288c03a6823';
Table tfl_acquistions
CREATE TABLE `tfl_acquistions` (
`id` VARCHAR(32) NOT NULL DEFAULT '',
`address` VARCHAR(100) NOT NULL DEFAULT '',
`city` VARCHAR(50) NOT NULL DEFAULT '',
`state` VARCHAR(10) NOT NULL DEFAULT '',
`zip` VARCHAR(10) NOT NULL DEFAULT '',
`county` VARCHAR(50) NOT NULL DEFAULT '',
`country` VARCHAR(50) NOT NULL DEFAULT '',
`status` ENUM('Y','N') NOT NULL DEFAULT 'Y',
`customer_case` VARCHAR(25) NOT NULL DEFAULT '',
`circle_id` INT(11) NOT NULL DEFAULT '0',
`visneta_id` VARCHAR(45) NOT NULL DEFAULT '',
`add_date` DATE NOT NULL DEFAULT '0000-00-00',
`apt_no` VARCHAR(10) NOT NULL DEFAULT '',
`profile_picture` VARCHAR(256) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
INDEX `address` (`address`),
INDEX `city` (`city`),
INDEX `state` (`state`),
INDEX `zip` (`zip`),
INDEX `status` (`status`),
INDEX `customer_case` (`customer_case`),
INDEX `circle_id` (`circle_id`),
INDEX `visneta_id` (`visneta_id`)
)
Table tfl_property_attributes
CREATE TABLE `tfl_property_attributes` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`property_id` VARCHAR(32) NOT NULL,
`attribute_id` INT(11) NOT NULL DEFAULT '0',
`value` VARCHAR(500) NOT NULL DEFAULT '',
`update_date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`update_by` INT(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
INDEX `attribute_id` (`attribute_id`),
INDEX `property_id` (`property_id`),
INDEX `property_id_2` (`property_id`, `attribute_id`)
)
I am on a task to optimized this query and i am new .... any help is appreciated
Try:
SELECT * FROM
tfl_acquistions a JOIN
tfl_property_attributes b ON a.id = b.property_id WHERE
b.property_id = '53a8288c03a6823' AND b.attribute_id = '111';
This way MySQL will be able to use the index property_id_2 (property_id, attribute_id) you have created on the second table. Currently, it can't use any indexes.
Try putting EXPLAIN keyword in front of queries to see how MySQL plans to perform them, you'll see that your previous query does not use any index.

Joins in MySQL are not working

I am a beginner in MySQL and trying to create a join query in MySQL.
My first SQL query is as below which displays the 2 columns votes and post
SELECT votes, post
FROM `wp_votes` where votes!=''
GROUP BY votes,post asc LIMIT 0 , 30
**Second table is where the posts are **
SELECT *
FROM `wp_posts`
LIMIT 0 , 30
What i wanna do is create a join so that it display all records from wp_posts table WHERE wp_post.ID=wp_votes.post, Also have to check if wp_votes.votes!=''
I tried the following but i am stuck on it
SELECT * FROM wp_posts join wp_votes ON wp_posts.ID =wp_votes.post
Table Structure below
CREATE TABLE IF NOT EXISTS `wp_posts` (
`ID` bigint(20) unsigned NOT NULL auto_increment,
`post_author` bigint(20) unsigned NOT NULL default '0',
`post_date` datetime NOT NULL default '0000-00-00 00:00:00',
`post_date_gmt` datetime NOT NULL default '0000-00-00 00:00:00',
`post_content` longtext NOT NULL,
`post_title` text NOT NULL,
`post_excerpt` text NOT NULL,
`post_status` varchar(20) NOT NULL default 'publish',
`comment_status` varchar(20) NOT NULL default 'open',
`ping_status` varchar(20) NOT NULL default 'open',
`post_password` varchar(20) NOT NULL default '',
`post_name` varchar(200) NOT NULL default '',
`to_ping` text NOT NULL,
`pinged` text NOT NULL,
`post_modified` datetime NOT NULL default '0000-00-00 00:00:00',
`post_modified_gmt` datetime NOT NULL default '0000-00-00 00:00:00',
`post_content_filtered` longtext NOT NULL,
`post_parent` bigint(20) unsigned NOT NULL default '0',
`guid` varchar(255) NOT NULL default '',
`menu_order` int(11) NOT NULL default '0',
`post_type` varchar(20) NOT NULL default 'post',
`post_mime_type` varchar(100) NOT NULL default '',
`comment_count` bigint(20) NOT NULL default '0',
PRIMARY KEY (`ID`),
KEY `post_name` (`post_name`),
KEY `type_status_date` (`post_type`,`post_status`,`post_date`,`ID`),
KEY `post_parent` (`post_parent`),
KEY `post_author` (`post_author`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=4570 ;
--
-- Table structure for table `wp_votes`
--
CREATE TABLE IF NOT EXISTS `wp_votes` (
`ID` int(11) NOT NULL auto_increment,
`post` int(11) NOT NULL,
`votes` text NOT NULL,
`guests` text NOT NULL,
`usersinks` text NOT NULL,
`guestsinks` text NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1052 ;
SELECT a.votes, a.post,
b.*
FROM wp_votes a
INNER JOIN wp_Post b
ON a.post = b.ID
WHERE a.votes <> ''
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins

How to optimize my query? Exporting Wordpress posts with category and tag list

I wrote query for export posts.
SELECT
post_name,
post_content,
Categories,
Tags
FROM
-- posts
wp_posts as p
-- categories
LEFT JOIN
(SELECT
object_id as cat_obj_id,
GROUP_CONCAT(cat_term.name) as Categories
FROM
wp_term_relationships AS cat_r
JOIN wp_term_taxonomy AS cat_tax
ON cat_r.term_taxonomy_id = cat_tax.term_taxonomy_id
JOIN wp_terms AS cat_term
ON cat_tax.term_id = cat_term.term_id
WHERE cat_tax.taxonomy="category"
GROUP by object_id)
as c
ON p.id = c.cat_obj_id
-- tags
LEFT JOIN
(SELECT
object_id as tag_obj_id,
GROUP_CONCAT(tag_term.name) as Tags
FROM
wp_term_relationships AS tag_r
JOIN wp_term_taxonomy AS tag_tax
ON tag_r.term_taxonomy_id = tag_tax.term_taxonomy_id
JOIN wp_terms AS tag_term
ON tag_tax.term_id = tag_term.term_id
WHERE tag_tax.taxonomy="post_tag"
GROUP by object_id)
as t
ON p.id = t.tag_obj_id
Table schemas:
CREATE TABLE `wp_term_taxonomy` (
`term_taxonomy_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`term_id` bigint(20) unsigned NOT NULL DEFAULT '0',
`taxonomy` varchar(32) NOT NULL DEFAULT '',
`description` longtext NOT NULL,
`parent` bigint(20) unsigned NOT NULL DEFAULT '0',
`count` bigint(20) NOT NULL DEFAULT '0',
PRIMARY KEY (`term_taxonomy_id`),
UNIQUE KEY `term_id_taxonomy` (`term_id`,`taxonomy`),
KEY `taxonomy` (`taxonomy`)
) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=utf8$$
CREATE TABLE `wp_term_relationships` (
`object_id` bigint(20) unsigned NOT NULL DEFAULT '0',
`term_taxonomy_id` bigint(20) unsigned NOT NULL DEFAULT '0',
`term_order` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`object_id`,`term_taxonomy_id`),
KEY `term_taxonomy_id` (`term_taxonomy_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8$$
CREATE TABLE `wp_terms` (
`term_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(200) NOT NULL DEFAULT '',
`slug` varchar(200) NOT NULL DEFAULT '',
`term_group` bigint(10) NOT NULL DEFAULT '0',
PRIMARY KEY (`term_id`),
UNIQUE KEY `slug` (`slug`),
KEY `name` (`name`)
) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=utf8$$
CREATE TABLE `wp_posts` (
`ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`post_author` bigint(20) unsigned NOT NULL DEFAULT '0',
`post_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`post_date_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`post_content` longtext NOT NULL,
`post_title` text NOT NULL,
`post_excerpt` text NOT NULL,
`post_status` varchar(20) NOT NULL DEFAULT 'publish',
`comment_status` varchar(20) NOT NULL DEFAULT 'open',
`ping_status` varchar(20) NOT NULL DEFAULT 'open',
`post_password` varchar(20) NOT NULL DEFAULT '',
`post_name` varchar(200) NOT NULL DEFAULT '',
`to_ping` text NOT NULL,
`pinged` text NOT NULL,
`post_modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`post_modified_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`post_content_filtered` longtext NOT NULL,
`post_parent` bigint(20) unsigned NOT NULL DEFAULT '0',
`guid` varchar(255) NOT NULL DEFAULT '',
`menu_order` int(11) NOT NULL DEFAULT '0',
`post_type` varchar(20) NOT NULL DEFAULT 'post',
`post_mime_type` varchar(100) NOT NULL DEFAULT '',
`comment_count` bigint(20) NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`),
KEY `post_name` (`post_name`),
KEY `type_status_date` (`post_type`,`post_status`,`post_date`,`ID`),
KEY `post_parent` (`post_parent`),
KEY `post_author` (`post_author`)
) ENGINE=MyISAM AUTO_INCREMENT=9082 DEFAULT CHARSET=utf8$$
EXPLAIN:
Running this query on 1000 posts database takes 72 seconds (execute under 1 sec, fetching takes forever). Is there any way to make it faster, without temporary tables to store categories and tags?
I discovered, that my big query runs horribly slow when there are no records on one of subqueries, that are LEFT JOIN'ed.
To workaround this - I created temporary tables from subqueries and I replaced subqueries with these temporary tables.
Here is my SQL.
-- 1.1. Creating table for post categories
create table if not exists temp_categories
(
ID bigint not null AUTO_INCREMENT,
Categories text not null,
PRIMARY KEY (ID)
) DEFAULT CHARSET=utf8;
-- 1.2. Filling table temp_categories
INSERT INTO temp_categories(ID, Categories)
SELECT
'object_id' AS ID, -- post ID
GROUP_CONCAT(cat_term.name ORDER BY cat_term.name) AS Categories -- comma separated category list
FROM
wp_term_relationships AS cat_r
JOIN wp_term_taxonomy AS cat_tax
ON cat_r.term_taxonomy_id = cat_tax.term_taxonomy_id
JOIN wp_terms AS cat_term
ON cat_tax.term_id = cat_term.term_id
WHERE cat_tax.taxonomy="category"
GROUP by object_id;
-- 2.1. Creating table for post tags
create table temp_tags
(
ID bigint not null AUTO_INCREMENT,
Tags text not null,
PRIMARY KEY (ID)
) DEFAULT CHARSET=utf8 ;
-- 2.2. Filling table temp_tags
INSERT INTO exp_tagi(ID, Tagi)
SELECT
object_id AS ID, --post ID
GROUP_CONCAT(tag_term.name ORDER BY tag_term.name) AS Tags -- comma separated tag list
FROM
wp_term_relationships AS tag_r
JOIN wp_term_taxonomy AS tag_tax
ON tag_r.term_taxonomy_id = tag_tax.term_taxonomy_id
JOIN wp_terms AS tag_term
ON tag_tax.term_id = tag_term.term_id
WHERE tag_tax.taxonomy="post_tag"
GROUP by object_id;
-- 3. Exporting posts
SELECT
p.id AS id,
p.post_title AS Title,
p.post_content AS Content,
k.Categories AS Categories,
t.Tags AS Tags,
IF(p.post_status = 'publish', 1, 0) AS Published
FROM
wp_posts p
left join temp_categories k
on p.id = k.id
left join temp_tags t
on p.id = t.id
WHERE post_status in('publish', 'draft')
ORDER BY id;
-- 4. Deleting temporary tables
DROP TABLE temp_categories;
DROP TABLE temp_tags;
I could use TEMPORARY tables (no need for delete, they disappear when MySQL session ends), but I didnt because my PHP app ends MySQL session after each query.