Get 50k rows faster with subqueries - Laravel 5.6 - mysql

The below query is to get the candidate's details from the table which has 50k rows. Including jobs, regions, and employment types. A candidate has basic details with employment type, jobs, regions are in another table with foreign key relation.
$candidates = DB::table('candidates')
->join('role_users', function($join){
$join->on('candidates.user_id', '=', 'role_users.user_id');
$join->where('role_users.role_id', 6);
})
->join('candidate_statuses', 'candidates.candidate_status_id', '=', 'candidate_statuses.id')
->join('employment_types', 'candidates.employment_types_id', '=', 'employment_types.id')
->select(
'candidates.id',
'candidates.user_id',
'candidates.candidate_code',
'candidates.full_name as name',
'employment_types.title AS employment_type',
DB::raw("(SELECT GROUP_CONCAT(candidate_jobs.job_id SEPARATOR ',') FROM candidate_jobs WHERE candidate_jobs.candidate_id = candidates.id) as job_ids"),
DB::raw("(SELECT GROUP_CONCAT(regions.name SEPARATOR ',') FROM candidate_regions INNER JOIN regions ON regions.id=candidate_regions.region_id WHERE candidate_regions.candidate_id = candidates.id) as regions"),
'role_users.email',
'role_users.login_at',
'candidates.is_deleted')
->where('candidates.candidate_status_id', '!=' , 6)
->where('candidates.is_deleted', $request->is_deleted)
->orderBy('candidates.first_name')
->groupBy('candidates.id')
->paginate(10);
}
select `candidates`.`id`, `candidates`.`user_id`, `candidates`.`candidate_code`,
`candidates`.`first_name`,
`candidates`.`last_name`, `candidates`.`full_name` as `name`,
`candidates`.`profile_img`, `candidates`.`candidate_status_id`,
`candidates`.`employment_types_id`,
`employment_types`.`title` as `employment_type`,
(
SELECT GROUP_CONCAT(candidate_jobs.job_id SEPARATOR ',')
FROM candidate_jobs
WHERE candidate_jobs.candidate_id = candidates.id
) as job_ids,
(
SELECT GROUP_CONCAT(regions.name SEPARATOR ',')
FROM candidate_regions
INNER JOIN regions ON regions.id=candidate_regions.region_id
WHERE candidate_regions.candidate_id = candidates.id
) as regions,
`candidates`.`formatted_mobile_number`, `candidates`.`place`,
`candidates`.`post_code`, `role_users`.`email`, `role_users`.`login_at`,
`role_users`.`email`, `candidates`.`has_access`, `candidates`.`is_deleted`
from `candidates`
inner join `role_users` ON `candidates`.`user_id` = `role_users`.`user_id`
and `role_users`.`role_id` = ?
inner join `candidate_statuses`
ON `candidates`.`candidate_status_id` = `candidate_statuses`.`id`
inner join `employment_types`
ON `candidates`.`employment_types_id` = `employment_types`.`id`
where (`candidates`.`candidate_status_id` in (?))
and `candidates`.`candidate_status_id` != ?
and `candidates`.`is_deleted` = ?
group by `candidates`.`id`
order by `candidates`.`first_name` asc
It takes 2/ 3 seconds to get the result in my local machine but in production takes too long time.
Can anyone please help?

It seems like the second part is unnecessary:
`candidates`.`candidate_status_id` in (?))
and `candidates`.`candidate_status_id` != ?
Making these match avoids an extra pass over the results
group by `first_name`, `id`
order by `first_name` asc, id
Possibly helpful indexes:
candidates: INDEX(candidate_status_id, is_deleted, first_name, id, user_id)
role_users: INDEX(user_id, email, login_at, role_id)
candidate_jobs: INDEX(candidate_id, job_id)
candidate_regions: INDEX(candidate_id, region_id)

Related

MySQL Find Most Recent/Largest Record Per Group by order by

MySQL Find Most Recent/Largest Record Per Group by order by, and how can i minimize / shorten this query and every time it returns the first row value of the group, whereas i like to select the last row value of a group, and sort the values based on ja.id ? I know this is a bad query can anyone suggest or provide me solution to shorten this query . I have used all the necessary Column Indexes in all the tables. How to shorten the query without the use of union all .both the queries in union all are same expect in the where statement.
SELECT
a.previous_status,
a.rejected_status,
a.rejection_reason_text,
a.rejection_reason,
a.rjaId,
a.refer_applied_status,
a.title,
a.playerId,
a.gameId,
a.gamePostDate,
a.game_referal_amount,
a.country,
a.country_name,
a.state,
a.location,
a.state_abb,
a.game_type,
a.appliedId,
a.appliedStatus,
a.admin_review,
a.is_req_referal_check,
a.memberId,
a.appliedEmail,
a.game_id,
a.referred_id,
a.memStateAbb,
a.memState,
a.memZipcode,
a.memCity,
a.memCountryNme,
a.memCountry,
a.appliedMemberName,
a.first_name,
a.primary_contact,
a.last_name,
a.addressbookImage,
a.userImage,
a.last_login,
a.user_experience_year,
a.user_experience_month,
a.current_designation,
a.current_player,
a.appliedDate,
a.addressbook_id,
a.joiningdate,
a.gameStatus,
a.gameReferalAmountType,
a.gameFreezeStatus,
a.gameFreezeMsg,
a.app_assign_back_to_rp_count,
a.applied_source,
a.max_id,
a.gamesApplied,
a.gamesAppliedId,
SUM(a.totalgameApplied) AS totalgameApplied,
a.application_assign_to_rp_status,
a.rpAppliedSource,
a.applied_on
FROM
(
(
SELECT
ja.previous_status,
ja.rejected_status,
ja.rejection_reason_text,
ja.rejection_reason,
rja.id AS rjaId,
rja. STATUS AS refer_applied_status,
jp.title,
jp.user_user_id AS playerId,
jp.id AS gameId,
jp.posted_on AS gamePostDate,
jp.game_referal_amount,
jp.country,
jp.country_name,
jp.state,
jp.location,
jp.state_abb,
jp.game_type,
ja.id AS appliedId,
IFNULL(ja. STATUS, '') AS appliedStatus,
IFNULL(ja.admin_review, '') AS admin_review,
ja.is_req_referal_check,
usr.id AS memberId,
rja.email AS appliedEmail,
rja.game_id,
rja.referred_id,
mem.state_abb AS memStateAbb,
mem.state AS memState,
mem.zipcode AS memZipcode,
mem.city AS memCity,
mem.country_name AS memCountryNme,
mem.country_code AS memCountry,
usc. NAME AS appliedMemberName,
usc.first_name,
IFNULL(
mem.primary_contact,
usc.phone_number
) AS primary_contact,
usc.last_name,
usc.profileimage_path AS addressbookImage,
usr.profile_image AS userImage,
usr.last_login,
mem.user_experience_year,
mem.user_experience_month,
mem.current_designation,
mem.current_player,
rja.create_date AS appliedDate,
rja.addressbook_id,
IFNULL(ja.joining_date, '') AS joiningdate,
jp. STATUS AS gameStatus,
jp.games_referal_amount_type AS gameReferalAmountType,
jp.game_freeze_status AS gameFreezeStatus,
jp.game_freeze_message AS gameFreezeMsg,
ja.app_assign_back_to_rp_count,
ja.applied_source,
MAX(rja.id) AS max_id,
GROUP_CONCAT(
jp.title
ORDER BY
rja.create_date DESC
) AS gamesApplied,
GROUP_CONCAT(DISTINCT(jp.id)) AS gamesAppliedId,
COUNT(DISTINCT(jp.id)) totalgameApplied,
ja.application_assign_to_rp_status,
1 AS rpAppliedSource,
rja.create_date AS applied_on
FROM
(`refer_gameapplied` AS rja)
JOIN `games_post` AS jp ON `jp`.`id` = `rja`.`game_id`
JOIN `user_socialconnections` AS usc ON `rja`.`addressbook_id` = `usc`.`id`
LEFT JOIN `user_user` AS usr ON `usr`.`email` = `rja`.`email`
LEFT JOIN `user_member` AS mem ON `mem`.`user_id` = `usr`.`id`
LEFT JOIN `game_applied` AS ja ON `ja`.`id` = `rja`.`applied_id`
WHERE
`rja`.`referby_id` = '2389'
GROUP BY
`rja`.`email`
)
UNION ALL
(
SELECT
ja.previous_status,
ja.rejected_status,
ja.rejection_reason_text,
ja.rejection_reason,
jr.id AS rjaId,
jrtm. STATUS AS refer_applied_status,
jp.title,
jp.user_user_id AS playerId,
jp.id AS gameId,
jp.posted_on AS gamePostDate,
jp.game_referal_amount,
jp.country,
jp.country_name,
jp.state,
jp.location,
jp.state_abb,
jp.game_type,
ja.id AS appliedId,
IFNULL(ja. STATUS, '') AS appliedStatus,
IFNULL(ja.admin_review, '') AS admin_review,
ja.is_req_referal_check,
usr.id AS memberId,
jrtm.referto_email AS refappliedEmail,
jr.game_id,
jrtm.id,
mem.state_abb AS memStateAbb,
mem.state AS memState,
mem.zipcode AS memZipcode,
mem.city AS memCity,
mem.country_name AS memCountryNme,
mem.country_code AS memCountry,
usc. NAME AS appliedMemberName,
usc.first_name,
IFNULL(
mem.primary_contact,
usc.phone_number
) AS primary_contact,
usc.last_name,
usc.profileimage_path AS addressbookImage,
usr.profile_image AS userImage,
usr.last_login,
mem.user_experience_year,
mem.user_experience_month,
mem.current_designation,
mem.current_player,
jrtm.refer_on AS appliedDate,
jrtm.referto_addressbookid,
IFNULL(ja.joining_date, '') AS joiningdate,
jp. STATUS AS gameStatus,
jp.games_referal_amount_type AS gameReferalAmountType,
jp.game_freeze_status AS gameFreezeStatus,
jp.game_freeze_message AS gameFreezeMsg,
ja.app_assign_back_to_rp_count,
ja.applied_source,
MAX(jrtm.id) AS max_id,
GROUP_CONCAT(
jp.title
ORDER BY
jr.refer_on DESC
) AS gamesApplied,
GROUP_CONCAT(DISTINCT(jp.id)) AS gamesAppliedId,
COUNT(DISTINCT(jp.id)) totalgameApplied,
ja.application_assign_to_rp_status,
2 AS rpAppliedSource,
jrtm.refer_on AS applied_on
FROM
(`game_refer` AS jr)
JOIN `game_refer_to_member` AS jrtm ON `jrtm`.`rid` = `jr`.`id`
JOIN `games_post` AS jp ON `jp`.`id` = `jr`.`game_id`
JOIN `user_socialconnections` AS usc ON `jrtm`.`referto_addressbookid` = `usc`.`id`
LEFT JOIN `user_user` AS usr ON `usr`.`email` = `jrtm`.`referto_email`
LEFT JOIN `user_member` AS mem ON `mem`.`user_id` = `usr`.`id`
LEFT JOIN `game_applied` AS ja ON `ja`.`referred_by` = `jrtm`.`id`
WHERE
`jrtm`.`status` = '1'
AND `jr`.`referby_user_id` = '2389'
AND `jrtm`.`refer_source` NOT IN ('4')
GROUP BY
`jrtm`.`referto_email`
)
) a
GROUP BY
a.appliedEmail
ORDER BY
a.gamesAppliedId DESC
It sounds like a "groupwise-max" problem. I added a tag that you should research.
At least get rid of the columns that are not relevant to the question.
Try tossing the tables other than jrtm and jr to see if the performance problem persists. (I'm thinking that the LEFT JOINs may be red herrings.)
Try with one part of the UNION, then with the other. This may identify which of the two is more of a burden.
Some indexes to add:
rja: (referby_id, create_date)
jrtm: (status, referto_email)
jrtm: (rid, status, referto_email)
jr: (referby_user_id, refer_on)
DISTINCT is not a function. Don't use parents in DISTINCT(jp.id).

MySQL Query is slow (Joins/counts)

I have this query:
SELECT `assemblies`.`id`,
`assemblies`.`type`,
`assemblies`.`champion`,
`assemblies`.`name`,
`assemblies`.`author`,
`assemblies`.`githublastmod`,
( assemblies.forum IS NOT NULL ) AS forumExists,
Count(votes.id) AS votesCount,
Count(install_clicks.id) AS installCount,
Count(github_clicks.id) AS githubCount,
Count(forum_clicks.id) AS forumCount
FROM `assemblies`
INNER JOIN `votes`
ON `votes`.`assembly` = `assemblies`.`id`
INNER JOIN `install_clicks`
ON `install_clicks`.`assembly` = `assemblies`.`id`
INNER JOIN `github_clicks`
ON `github_clicks`.`assembly` = `assemblies`.`id`
INNER JOIN `forum_clicks`
ON `forum_clicks`.`assembly` = `assemblies`.`id`
WHERE `assemblies`.`type` = 'utility'
AND Unix_timestamp(Date(assemblies.githublastmod)) > '1419536536'
GROUP BY `assemblies`.`id`
ORDER BY `votescount` DESC,
`githublastmod` DESC
For some reason this query is very slow, I'm using the database engine MyISAM. I hope someone can help me out here :)
Explain command:
I believe this is a case where making the subqueries for the counts will make it run a lot faster (and the values will be correct).
The problem with the original query is the explosion of the number of intermediate rows: For each 'assembly', there were n1 votes, n2 installs, etc. That led to n1*n2*... rows per assembly.
SELECT `assemblies`.`id`, `assemblies`.`type`, `assemblies`.`champion`,
`assemblies`.`name`, `assemblies`.`author`, `assemblies`.`githublastmod`,
( assemblies.forum IS NOT NULL ) AS forumExists,
( SELECT Count(*)
FROM votes
WHERE `assembly` = `assemblies`.`id`
) AS votesCount,
( SELECT Count(*)
FROM install_clicks
WHERE `assembly` = `assemblies`.`id`
) AS installCount,
( SELECT Count(*)
FROM github_clicks
WHERE `assembly` = `assemblies`.`id`
) AS githubCount,
( SELECT Count(*)
FROM forum_clicks.id
WHERE `assembly` = `assemblies`.`id`
) AS forumCount
FROM `assemblies`
WHERE `assemblies`.`type` = 'utility'
AND Unix_timestamp(Date(assemblies.githublastmod)) > '1419536536'
ORDER BY `votescount` DESC, `githublastmod` DESC
Each secondary table needs an INDEX starting with assembly.
Your problem should be fixed using the right indices:
CREATE INDEX index_name_1 ON `votes`(`assembly`);
CREATE INDEX index_name_2 ON `install_clicks`(`assembly`);
CREATE INDEX index_name_3 ON `github_clicks`(`assembly`);
CREATE INDEX index_name_4 ON `forum_clicks`(`assembly`);
Try your query again after creating these indices and it should be quite faster.

mysql table views with conditions

I have an online store, two views because my products could come from either my packages table or sessions table. The prices are joined from the price table.
The two views work fine on their own, but when I combine there usage I get no results.
I want my shipping guy to only see the items he should ship, not the digital items, namely, those with delivery format equal to 'DVD'.
session view:
select
`ats_store`.`order`.`payment_type` AS `payment_type`,
`production_www`.`paypal_transactions`.`createdOn` AS `order_date`,
`production_www`.`paypal_transactions`.`FIRSTNAME` AS `firstname`,
`production_www`.`paypal_transactions`.`LASTNAME` AS `lastname`,
`ats_store`.`order`.`id` AS `order_id`,
`ats_store`.`order`.`customerid` AS `customerid`,
`ats_store`.`order`.`shipping_address_id` AS `shipping_address_id`,
`ats_store`.`order`.`status` AS `status`,
`ats_store`.`order_items`.`product_id` AS `product_id`,
`ats_store`.`shipping_address`.`country` AS `country`,
`ats_store`.`shipping_address`.`street_1` AS `street1`,
`ats_store`.`shipping_address`.`street_2` AS `street2`,
`ats_store`.`shipping_address`.`street_3` AS `street3`,
`ats_store`.`shipping_address`.`city` AS `city`,
`ats_store`.`shipping_address`.`state_and_province` AS `state`,
`ats_store`.`shipping_address`.`zip_code` AS `zip`,
group_concat(`production_cache_salesforce_repl`.`ats_conference_session__c`.`Name`,
'(',
`price`.`Delivery_Format__c`,
')'
order by `production_cache_salesforce_repl`.`ats_conference_session__c`.`sort_code__c` ASC
separator ',') AS `session_products`
from
(((((`ats_store`.`order`
left join `ats_store`.`shipping_address` ON ((`ats_store`.`shipping_address`.`id` = `ats_store`.`order`.`shipping_address_id`)))
join `ats_store`.`order_items` ON ((`ats_store`.`order_items`.`order_id` = `ats_store`.`order`.`id`)))
join `production_cache_salesforce_repl`.`ats_store_price__c` `price` ON ((`price`.`Id` = `ats_store`.`order_items`.`product_id`)))
join `production_cache_salesforce_repl`.`ats_conference_session__c` ON ((`production_cache_salesforce_repl`.`ats_conference_session__c`.`Id` = convert( `price`.`ATS_Conference_Session__c` using utf8))))
left join `production_www`.`paypal_transactions` ON ((`production_www`.`paypal_transactions`.`id` = `ats_store`.`order`.`paypal_transaction_id`)))
where
((`ats_store`.`order`.`shipping_address_id` <> -(1))
and (`production_www`.`paypal_transactions`.`COMMENT1` = 'ATS Web Store')
and (`production_www`.`paypal_transactions`.`RESPMSG` = 'Approved')
and (`price`.`Delivery_Format__c` = 'DVD'))
group by `ats_store`.`order`.`id`
order by `production_www`.`paypal_transactions`.`createdOn`
package view:
select
`ats_store`.`order`.`payment_type` AS `payment_type`,
`production_www`.`paypal_transactions`.`createdOn` AS `order_date`,
`production_www`.`paypal_transactions`.`FIRSTNAME` AS `firstname`,
`production_www`.`paypal_transactions`.`LASTNAME` AS `lastname`,
`ats_store`.`order`.`id` AS `order_id`,
`ats_store`.`order`.`customerid` AS `customerid`,
`ats_store`.`order`.`shipping_address_id` AS `shipping_address_id`,
`ats_store`.`order`.`status` AS `status`,
`ats_store`.`order_items`.`product_id` AS `product_id`,
`ats_store`.`shipping_address`.`country` AS `country`,
`ats_store`.`shipping_address`.`street_1` AS `street1`,
`ats_store`.`shipping_address`.`street_2` AS `street2`,
`ats_store`.`shipping_address`.`street_3` AS `street3`,
`ats_store`.`shipping_address`.`city` AS `city`,
`ats_store`.`shipping_address`.`state_and_province` AS `state`,
`ats_store`.`shipping_address`.`zip_code` AS `zip`,
`price`.`Delivery_Format__c` AS `delivery_format`,
group_concat(`production_cache_salesforce_repl`.`ats_store_package__c`.`Package_Code__c`,
'(',
`price`.`Delivery_Format__c`,
')'
order by `production_cache_salesforce_repl`.`ats_store_package__c`.`Package_Code__c` ASC
separator ',') AS `package_products`
from
(((((`ats_store`.`order`
left join `ats_store`.`shipping_address` ON ((`ats_store`.`shipping_address`.`id` = `ats_store`.`order`.`shipping_address_id`)))
join `ats_store`.`order_items` ON ((`ats_store`.`order_items`.`order_id` = `ats_store`.`order`.`id`)))
join `production_cache_salesforce_repl`.`ats_store_price__c` `price` ON ((`price`.`Id` = `ats_store`.`order_items`.`product_id`)))
join `production_cache_salesforce_repl`.`ats_store_package__c` ON ((`production_cache_salesforce_repl`.`ats_store_package__c`.`Id` = convert( `price`.`ATS_Store_Package__c` using utf8))))
left join `production_www`.`paypal_transactions` ON ((`production_www`.`paypal_transactions`.`id` = `ats_store`.`order`.`paypal_transaction_id`)))
where
((`ats_store`.`order`.`shipping_address_id` <> -(1))
and (`production_www`.`paypal_transactions`.`COMMENT1` = 'ATS Web Store')
and (`production_www`.`paypal_transactions`.`RESPMSG` = 'Approved')
and (`price`.`Delivery_Format__c` = 'DVD'))
group by `ats_store`.`order`.`id`
order by `production_www`.`paypal_transactions`.`createdOn`
Here is the query that uses both views:
select *,group_concat(pv.package_products,',',sv.session_products) as products from ats_store.shipping_orders_sessions_view sv,ats_store.shipping_orders_packages_view pv
where sv.order_id = pv.order_id
group by sv.order_id
If I remove from the VIEWS and (price.Delivery_Format__c= 'DVD') I can get the orders, but the digital and DVD products are shown. I only want my shipping guy to see items he should ship, the DVDs.
Assuming your two views are clean and working:
Let's work on that query that joins them.
Here's what you have, rewritten to use an explicit join.
select *, /* query with problems */
group_concat(pv.package_products,',',sv.session_products) as products
from ats_store.shipping_orders_sessions_view sv
join ats_store.shipping_orders_packages_view pv on sv.order_id = pv.order_id
group by sv.order_id
What's wrong here?
First, pro tip: don't use select * in complex queries.
Second, select * guarantees random nonsense in your output resultset because you're using a harmful nonstandard MySQL hackstension. Read this: http://dev.mysql.com/doc/refman/5.5/en/group-by-extensions.html You should mention each non-aggregated column in your result set in your GROUP BY clause.
Third, you probably want
GROUP_CONCAT(CONCAT(pv.package_products,',',sv.session_product)) AS products
to make sure you are using the aggregating function GROUP_CONCAT() properly.
So here is a better query.
select sv.order_id,
GROUP_CONCAT(CONCAT(pv.package_products,',',sv.session_product)) AS products
from ats_store.shipping_orders_sessions_view sv
join ats_store.shipping_orders_packages_view pv on sv.order_id = pv.order_id
group by sv.order_id
EDIT: This will yield a result set with one row per distinct order_id that mentions all the products in each order. If you wish to include only certain items, for example those with delivery_format = 'DVD', you need to add a WHERE clause. It looks like your package view exposes that column. So try this:
select sv.order_id,
GROUP_CONCAT(CONCAT(pv.package_products,',',sv.session_product)) AS products
from ats_store.shipping_orders_sessions_view sv
join ats_store.shipping_orders_packages_view pv on sv.order_id = pv.order_id
where pv.delivery_format = 'DVD'
group by sv.order_id
I don't understand your schema well enough to give you better advice than this. I can see that your views are quite complex.

how to avoid filesort on union all query

Please i have this query which uses filesort if combined(union all), but if executed separately works fine without file sort. Here i dont want to execute it separately but want to implement the union all option. Please someone should help.
(SELECT STRAIGHT_JOIN *,
topic_post_time,
topic_title,
topic_id AS tid,
p.userid AS profile_id,
Concat(first_name, ' ', last_name) AS poster_name,
Concat(first_name, '.', last_name) AS profile_name,
forum_id,
topic_last_post_time,
sch_name_abbrev,
picture_small_url,
profile_pix_upload_path,
profile_pix_upload_path,
LEFT(post_text, 100) AS post_text
FROM _forum_topics FORCE INDEX(topic_poster)
INNER JOIN _profile p
ON ( p.userid = _forum_topics.topic_poster )
INNER JOIN _users
ON p.userid = _users.userid
INNER JOIN _class
ON _users.classid = _class.classid
INNER JOIN _unit
ON _class.unitid = _unit.unitid
INNER JOIN _department
ON _unit.deptid = _department.deptid
INNER JOIN _faculty
ON _department.facid = _faculty.facid
INNER JOIN _university
ON ( _faculty.schid = _university.schid )
WHERE _forum_topics.sub_forum_id IN( 133, 134, 135, 136,
137, 138 )
ORDER BY topic_last_post_time DESC
LIMIT 0, 20)
UNION ALL
(SELECT STRAIGHT_JOIN *,
topic_post_time,
topic_title,
topic_id AS tid,
p.userid AS profile_id,
Concat(first_name, ' ', last_name) AS poster_name,
Concat(first_name, '.', last_name) AS profile_name,
forum_id,
topic_last_post_time,
sch_name_abbrev,
picture_small_url,
profile_pix_upload_path,
profile_pix_upload_path,
LEFT(post_text, 100) AS post_text
FROM _sch_forum_topics s FORCE INDEX(topic_poster)
INNER JOIN _profile p
ON ( p.userid = s.topic_poster )
INNER JOIN _users
ON p.userid = _users.userid
INNER JOIN _class
ON _users.classid = _class.classid
INNER JOIN _unit
ON _class.unitid = _unit.unitid
INNER JOIN _department
ON _unit.deptid = _department.deptid
INNER JOIN _faculty
ON _department.facid = _faculty.facid
INNER JOIN _university
ON _faculty.schid = _university.schid
ORDER BY topic_last_post_time DESC
LIMIT 0, 20)
LIMIT
0, 20
It seems to me that the only difference is the WHERE clause. Just use an OR.
Also, ORDER BY is not accomplished in this context, not because MySQL is buggy, but because it does not have a logical meaning.
There is also an old MySQL bug which makes all UNIONs use temporary tables:
http://bugs.mysql.com/bug.php?id=50674
and ordering a temporary table generated by a query means filesort
#Federico
"There is also an old MySQL bug which makes all UNIONs use temporary tables: http://bugs.mysql.com/bug.php?id=50674 and ordering a temporary table generated by a query means filesort"
I've made an anwser because an comment doenst allow code formatting
C++ Source code off (file sql/sql_union.cc) MySQL 5.5.32 union looks like it always creates an temporary table..
See the code comments and function create_tmp_table
/*
Create a temporary table to store the result of select_union.
SYNOPSIS
select_union::create_result_table()
thd thread handle
column_types a list of items used to define columns of the
temporary table
is_union_distinct if set, the temporary table will eliminate
duplicates on insert
options create options
DESCRIPTION
Create a temporary table that is used to store the result of a UNION,
derived table, or a materialized cursor.
RETURN VALUE
0 The table has been created successfully.
1 create_tmp_table failed.
*/
bool
select_union::create_result_table(THD *thd_arg, List<Item> *column_types,
bool is_union_distinct, ulonglong options,
const char *alias)
{
DBUG_ASSERT(table == 0);
tmp_table_param.init();
tmp_table_param.field_count= column_types->elements;
if (! (table= create_tmp_table(thd_arg, &tmp_table_param, *column_types,
(ORDER*) 0, is_union_distinct, 1,
options, HA_POS_ERROR, alias)))

MySQL - Optimization select query

My query is taking 5 seconds to finish but it sounds to much for something so basic. I did an explain query:
https://www.dropbox.com/s/18pedm9n5fssz4e/localhost%20_%20localhost%20_%20logrede%20_%20phpMyAdmin%203.4.11.pdf
It is possible to you to help me optimize it?
Thanks :)
I've restructured the query using JOINs instead of a less readable WHERE clause. I see everything is based on the primary "material" table. So, my first suggestion is to use the "STRAIGHT_JOIN" clause to tell MySQL to do the query in the order you have listed.... otherwise, sometimes it tries to think for you and do some things in what could be an alternate "primary" table driving the query. All your other tables are basically "lookup values" tables.
Secondly... On each of the tables, I would specifically have the following indexes on the tables. I'm sure you already had on the primary keys of each table... but since your GROUP_CONCAT are getting a corresponding descriptive field from the table, I would include that column in the index. Here's the other reason... When a query is run and using the index, if the query does not have to go back to the raw table for the "other" columns, it doesn't have to. So, by having the description as part of the index, it can do the join AND get the description both from the index...
I would have an index on
material ( cdomaterial )
cliente ( idcliente, nome )
classeobra ( idclasse, sigla )
dma ( iddma, nome )
desenho( iddesenho, nome )
fornecedor ( idfornecedor, nome )
modelo ( idmodelo, nome )
fabricante ( idfabri, nome )
fornecido( codmaterial, preco )
unidade( idunidade, sigla )
tipofornecimento( idtipoforn, sigla )
So, the above said, I would run the following query...
SELECT STRAIGHT_JOIN
material.codmaterial,
cliente.nome as cliente,
tipofornecimento.sigla as fornecimento,
unidade.sigla as unidade,
GROUP_CONCAT(DISTINCT classeobra.sigla ORDER BY classeobra.idclasse SEPARATOR ', ') as classeobra,
GROUP_CONCAT(DISTINCT dma.nome ORDER BY dma.iddma SEPARATOR ', ') as dma,
GROUP_CONCAT(DISTINCT desenho.nome ORDER BY desenho.iddesenho SEPARATOR ', ') as desenho,
GROUP_CONCAT(DISTINCT fornecedor.nome ORDER BY fornecedor.idfornecedor SEPARATOR ', ') as fornecedor,
GROUP_CONCAT(DISTINCT modelo.nome ORDER BY modelo.idmodelo SEPARATOR ', ') as modelo,
GROUP_CONCAT(DISTINCT fabricante.nome ORDER BY fabricante.idfabri SEPARATOR ', ') as marca,
GROUP_CONCAT(DISTINCT fornecido.preco ORDER BY fornecido.preco SEPARATOR ', ') as preco
FROM
material
JOIN unidad
ON material.idunidade = unidade.idunidade
JOIN requisitado
ON material.codmaterial = requisitado.codmaterial
JOIN cliente
ON requisitado.idcliente = cliente.idcliente
JOIN tipofornecimento
ON requisitado.idtipoforn = tipofornecimento.idtipoforn
JOIN possuimodelo
ON material.codmaterial = possuimodelo.codmaterial
JOIN modelo
ON possuimodelo.idmodelo = modelo.idmodelo
JOIN pertence,
ON modelo.idmodelo = pertence.idmodelo
JOIN fabricante
ON pertence.idfabri = fabricante.idfabri
JOIN utilizadoclasseobra
ON material.codmaterial = utilizadoclasseobra.codmaterial
JOIN classeobra
ON utilizadoclasseobra.idclasse = classeobra.idclasse
JOIN possuidma
ON material.codmaterial = possuidma.codmaterial
JOIN dma
ON possuidma.iddma = dma.iddma
JOIN fornecido
ON material.codmaterial = fornecido.codmaterial
JOIN fornecedor
ON fornecido.idfornecedor = fornecedor.idfornecedor
JOIN possuidesenho
ON material.codmaterial = possuidesenho.codmaterial
JOIN desenho
ON possuidesenho.iddesenho = desenho.iddesenho
GROUP BY
material.codmaterial,
cliente.nome
ORDER BY
material.codmaterial ASC,
cliente.nome ASC ;