Suggestions on complex sql statement - mysql

SELECT `v`.*
, GROUP_CONCAT(DISTINCT(`gg`.genre_id)) AS `genre_ids`
, GROUP_CONCAT(DISTINCT(`gg`.genre_ru)) AS `genres`
, GROUP_CONCAT(DISTINCT(`tg`.tag_id)) AS `tags_ids`
, GROUP_CONCAT(DISTINCT(`tg`.name)) AS `tags`
FROM `video` AS `v`
LEFT JOIN `video_categories` AS `gc` ON gc.video_id = v.video_id
LEFT JOIN `video_genres` AS `gg` ON gg.genre_id = gc.genre_id
LEFT JOIN `tags_relations` AS `tr` ON tr.department=18 AND tr.parent_id = v.video_id
LEFT JOIN `tags` AS `tg` ON tg.tag_id = tr.tag_id
WHERE (v.video_id IN (
SELECT gc2.video_id
FROM video_categories gc2
WHERE gc2.genre_id IN(44)
GROUP BY gc2.video_id
HAVING COUNT(gc2.video_id)=1))
AND (v.video_id IN (
SELECT gc2.parent_id
FROM tags_relations gc2
WHERE gc2.tag_id IN(14) AND gc2.department=18
GROUP BY gc2.parent_id
HAVING COUNT(gc2.parent_id)=1))
GROUP BY `v`.`video_id`
ORDER BY `v`.`video_id` DESC
Query takes 0.4s~ to run. It's because of subquery in WHERE statement:
v.video_id IN (
SELECT gc2.parent_id
FROM tags_relations gc2
WHERE gc2.tag_id IN(14) AND gc2.department=18
GROUP BY gc2.parent_id
HAVING COUNT(gc2.parent_id)=1
)
Without it, it runs 0.07s~
Maybe try something with advanced joins? shy
Thanks ;)

In MySQL, never use WHERE in (SELECT ... it is notoriously slow.
Use a join instead:
SELECT `v`.*
, GROUP_CONCAT(DISTINCT(`gg`.genre_id)) AS `genre_ids`
, GROUP_CONCAT(DISTINCT(`gg`.genre_ru)) AS `genres`
, GROUP_CONCAT(DISTINCT(`tg`.tag_id)) AS `tags_ids`
, GROUP_CONCAT(DISTINCT(`tg`.name)) AS `tags`
FROM video AS v
INNER JOIN video_categories AS gc ON gc.video_id = v.video_id
AND gc2.genre_id = '44'
LEFT JOIN video_genres AS gg ON gg.genre_id = gc.genre_id
LEFT JOIN tags_relations AS tr ON tr.department=18 AND tr.parent_id = v.video_id
LEFT JOIN tags AS tg ON tg.tag_id = tr.tag_id
INNER JOIN tags_relations tr2 ON (tr2.parent_id = v.video_id
AND tr2.tag_id = 14 AND tr2.department=18
GROUP BY `v`.`video_id`
ORDER BY `v`.`video_id` DESC

SELECT `v`.*
, GROUP_CONCAT(DISTINCT(`gg`.genre_id)) AS `genre_ids`
, GROUP_CONCAT(DISTINCT(`gg`.genre_ru)) AS `genres`
, GROUP_CONCAT(DISTINCT(`tg`.tag_id)) AS `tags_ids`
, GROUP_CONCAT(DISTINCT(`tg`.name)) AS `tags`
FROM `video` AS `v`
LEFT JOIN `video_categories` AS `gc` ON gc.video_id = v.video_id
LEFT JOIN `video_genres` AS `gg` ON gg.genre_id = gc.genre_id
LEFT JOIN `tags_relations` AS `tr` ON tr.department=18 AND tr.parent_id = v.video_id
LEFT JOIN `tags` AS `tg` ON tg.tag_id = tr.tag_id
JOIN (
SELECT gc2.video_id
FROM video_categories gc2
WHERE gc2.genre_id IN(44)
GROUP BY gc2.video_id
HAVING COUNT(gc2.video_id)=1
) vc ON v.video_id = vc.video_id
JOIN (
SELECT gc2.parent_id
FROM tags_relations gc2
WHERE gc2.tag_id IN(14) AND gc2.department=18
GROUP BY gc2.parent_id
HAVING COUNT(gc2.parent_id)=1
) tr ON v.video_id = tr.parent_id
GROUP BY `v`.`video_id`
ORDER BY `v`.`video_id` DESC
Edit:
I took a closer look at your query and think it can be reduced to the following:
SELECT `v1`.*
, GROUP_CONCAT(DISTINCT(`gg`.genre_id)) AS `genre_ids`
, GROUP_CONCAT(DISTINCT(`gg`.genre_ru)) AS `genres`
, GROUP_CONCAT(DISTINCT(`tg`.tag_id)) AS `tags_ids`
, GROUP_CONCAT(DISTINCT(`tg`.name)) AS `tags`
FROM (
SELECT v.*
FROM `video` AS `v`
LEFT JOIN `video_categories` AS `gc` ON gc.video_id = v.video_id
LEFT JOIN `tags_relations` AS `tr` ON tr.parent_id = v.video_id
WHERE gc.genre_id IN(44)
AND tr.tag_id IN(14)
AND tr.department=18
GROUP BY `v`.`video_id`
HAVING COUNT(*) = 1
) v1
LEFT JOIN `video_genres` AS `gg` ON gg.genre_id = gc.genre_id
LEFT JOIN `tags` AS `tg` ON tg.tag_id = tr.tag_id
GROUP BY v1.video_id
ORDER BY v1.video_id DESC

Related

How can I speed up this query with mysqli?

I have this query and it take 117 seconds to get 100000 rows can me get all this rows on 5 seconds or 10 seconds?
SELECT
`nas`.`nasname`,
`nas`.`api_username`,
`nas`.`api_password`,
`nas`.`api_port`,
`nas`.`secret`,
`nas`.`up_by`,
COALESCE(`nas`.`api_is_enabled`,'0') as `api_is_en`,
`radacct`.`nasipaddress`,
`radcheck`.`address_list_name`,
`radcheck`.`address_val`,
`radacct`.`framedipaddress`,
`radacct`.`callingstationid`,
`radacct`.`radacctid` as `id_session`,
`radacct`.`framedprotocol`,
`radacct`.`username`,
`radacct`.`last_speed` ,
`radacct`.`acctsessionid` as `acctsessionid`,
`radip`.`value` as `ip_address`,
`radmac`.`value` as `mac_address`,
`radcount`.`value` as `simul_sess`,
COUNT(`radacct`.`radacctid`) as count_login ,
COALESCE(`card_users`.`id`,0) as `id_card`,
COALESCE(`card_users`.`download_qouta`,`userinfo`.`in_down`) *1024*1024 as `down_qouta`,
COALESCE(`card_users`.`upload_qouta`,`userinfo`.`in_up`) *1024*1024 as `up_qouta`,
COALESCE(`card_users`.`all_quota`,`userinfo`.`av_qouta`) *1024*1024 as `av_qouta`,
`card_users`.`date_end_card` as `date_end_card`,
`card_users`.`val_date` as `val_date`,
`card_users`.`per_second` as `per_second`,
`card_users`.`at_the_first_login` as `at_the_first_login`,
`card_users`.`exp_first_login` as `exp_first_login`,
`card_users`.`val_time_exp` as `val_time_exp`,
`card_users`.`time_cards_exp` as `time_cards_exp`,
`card_users`.`exp_quota` as `exp_quota`,
`card_users`.`exp_date` as `exp_date`,
`userinfo`.`updatedate` as `updatedate`,
`userinfo`.`divi_down_speed_slm` as `divi_down_speed_slm`,
`userinfo`.`divi_up_speed_slm` as `divi_up_speed_slm`,
`userinfo`.`arr_days` as `u_arr_days`,
`userinfo`.`value_choice` as `u_value_choice`,
`userinfo`.`last_end_day` as `last_end_day`,
`userinfo`.`macs` as `macs`,
`p`.`profile_name` as `profile_name`,
`p`.`daily_down_qouta`*1024*1024 as `down_daily_qouta`,
`p`.`daily_up_qouta`*1024*1024 as `up_daily_qouta`,
`p`.`daily_profile_qouta`*1024*1024 as `daily_profile_qouta`,
`p`.`online_time` as `online_time`,
`p`.`hours_min` as `hours_min`,
`p`.`daily_online_time` as `daily_online_time`,
`p`.`daily_hours_min` as `daily_hours_min`,
`p`.`bandwidth_time` as `bandwidth_time`,
`p`.`daily_expire_service` as `daily_expire_service`,
`p`.`qouta_expire_service` as `qouta_expire_service`,
`p`.`profile_expire_service` as `profile_expire_service`,
`p`.`sp_up` as `sp_up`,
`p`.`sp_down` as `sp_down`,
`p`.`ch_day_end` as `ch_day_end`,
`p`.`set_day_end` as `set_day_end`,
`p`.`percent` as `percent`,
`p`.`arr_days` as `p_arr_days`,
`p`.`value_choice` as `p_value_choice`,
`r1`.`value` as `value_exp`,
`p1`.`bandwidth_time` as `band_exp`,
`p1`.`percent` as `percent_exp`,
`r2`.`value` as `val_address_exp_list`,
`r3`.`value` as `value_exp_daily`,
`p3`.`bandwidth_time` as `band_daily_exp`,
`p3`.`percent` as `percent_daily_exp`,
`r4`.`value` as `val_address_exp_daily_list`,
`r5`.`value` as `value_exp_serv`,
`p3`.`bandwidth_time` as `band_serv_exp`,
`p3`.`percent` as `percent_serv_exp`,
`r6`.`value` as `val_address_exp_serv_list`,
`r7`.`value` as `value_now`,
`r8`.`value` as `val_address_list`,
COALESCE(ROUND(time_to_sec(`userinfo`.`online_time`)),0) as `t_online_time` ,
COALESCE(ROUND(time_to_sec(`userinfo`.`daily_online_time`)),0) as `d_online_time`,
UNIX_TIMESTAMP(STR_TO_DATE(`radexp`.`value`, '%d %b %Y %H:%i')) as `exp_user`,
`radacct`.`callingstationid` as `callingstationid`,
UNIX_TIMESTAMP(STR_TO_DATE(`radacct`.`acctstarttime`, '%Y-%m-%d %H:%i:%s')) as `session_st_date`
FROM `radacct`
INNER JOIN `radcheck`
ON `radacct`.`username` = `radcheck`.`username`
AND `radcheck`.`attribute` = 'Cleartext-Password'
INNER JOIN `radusergroup` `r9`
ON `r9`.`username` = `radcheck`.`username`
LEFT JOIN `userinfo`
ON `userinfo`.`username` = `r9`.`username`
LEFT JOIN (
SELECT SUM(`radacct`.`acctinputoctets`) as `up_today`
, SUM(`radacct`.`acctoutputoctets`) as `down_today`
, SUM(`radacct`.`acctsessiontime`) as `daily_time`
, `radacct`.`username`
FROM `radacct`
WHERE DATE_FORMAT(STR_TO_DATE(`acctstarttime`,'%Y-%m-%d %H:%i:%s'),'%Y-%m-%d') = DATE_FORMAT(NOW(),'%Y-%m-%d')
GROUP BY `username`
) as `rad2`
ON `rad2`.`username` = `r9`.`username`
INNER JOIN `nas`
ON `nas`.`nasname`=`radacct`.`nasipaddress`
LEFT JOIN `profiles` `p`
ON `p`.`profile_name` = `r9`.`groupname`
LEFT JOIN `profiles` `p1`
ON `p1`.`id` = `p`.`qouta_expire_service`
LEFT JOIN `profiles` `p2`
ON `p2`.`id` = `p`.`daily_expire_service`
LEFT JOIN `profiles` `p3`
ON `p3`.`id` = `p`.`profile_expire_service`
LEFT JOIN `radgroupreply` `r1`
ON `r1`.`groupname` = `p1`.`profile_name`
AND `r1`.`attribute` = 'Mikrotik-Rate-Limit'
LEFT JOIN `radgroupreply` `r2`
ON `r2`.`groupname` = `p1`.`profile_name`
AND `r2`.`attribute` = 'Mikrotik-Address-List'
LEFT JOIN `radgroupreply` `r3`
ON `r3`.`groupname` = `p2`.`profile_name`
AND `r3`.`attribute` = 'Mikrotik-Rate-Limit'
LEFT JOIN `radgroupreply` `r4`
ON `r4`.`groupname` = `p2`.`profile_name`
AND `r4`.`attribute` = 'Mikrotik-Address-List'
LEFT JOIN `radgroupreply` `r5`
ON `r5`.`groupname` = `p3`.`profile_name`
AND `r5`.`attribute` = 'Mikrotik-Rate-Limit'
LEFT JOIN `radgroupreply` `r6`
ON `r6`.`groupname` = `p3`.`profile_name`
AND `r6`.`attribute` = 'Mikrotik-Address-List'
LEFT JOIN `radgroupreply` `r7`
ON `r7`.`groupname` = `p`.`profile_name`
AND `r7`.`attribute` = 'Mikrotik-Rate-Limit'
LEFT JOIN `radgroupreply` `r8`
ON `r8`.`groupname` = `p`.`profile_name`
AND `r8`.`attribute` = 'Mikrotik-Address-List'
LEFT JOIN `card_users`
ON `card_users`.`id` = `radcheck`.`id_card`
LEFT JOIN `radreply` as `radip`
ON `radip`.`username` = `r9`.`username`
AND `radip`.`attribute`='Framed-IP-Address'
LEFT JOIN `radcheck` as `radmac`
ON `radmac`.`username` = `r9`.`username`
AND `radmac`.`attribute`='Calling-Station-Id'
LEFT JOIN `radcheck` as `radcount`
ON `radcount`.`username` = `r9`.`username`
AND `radcount`.`attribute`='Simultaneous-Use'
LEFT JOIN `radcheck` as `radexp`
ON `radexp`.`username` = `r9`.`username`
AND `radexp`.`attribute`='Expiration'
WHERE ( radacct .AcctStopTime IS NULL
OR radacct.AcctStopTime = '0000-00-00 00:00:00')
GROUP BY `radacct`.`username`
When remove this from query it speed up 60%
LEFT JOIN (SELECT SUM(`radacct`.`acctinputoctets`) as `up_today`,
SUM(`radacct`.`acctoutputoctets`) as `down_today`,
SUM(`radacct`.`acctsessiontime`) as `daily_time`,
`radacct`.`username` FROM `radacct`
WHERE DATE_FORMAT(STR_TO_DATE(`acctstarttime`,'%Y-%m-%d %H:%i:%s'),'%Y-%m-%d') = DATE_FORMAT(NOW(),'%Y-%m-%d')
GROUP BY `username`) as `rad2` ON (`rad2`.`username` = `r9`.`username`)
I have index for all this tables so what is my problem ?
Note : I have pc have
cpu core i 5
ram 4 giga
this image for explain my table

MySQL how to do INNER JOIN accross many columns even if some as null.

I have added this simple example, to show the problem I am having. Say this is my database foo.
SELECT
`people`.`id`
, `people`.`name`
, `places`.`place_type`
, `places`.`aread`
, `family`.`family_count`
, `income`.`income_value`
, `income`.`average`
, `employment`.`address`
, `employment`.`duration`
FROM
`people`
INNER JOIN `places`
ON (`people`.`id` = `places`.`id`)
INNER JOIN `family`
ON (`people`.`id` = `family`.`id`)
INNER JOIN `income`
ON (`people`.`id` = `income`.`id`)
INNER JOIN `employment`
ON (`people`.`id` = `employment`.`id`) WHERE `people`.`full_name` = ? LIMIT 1
Now the issue here is that I get null values if people.id is not matching every id in the other columns. This is because not all of people with id are found in places, family, income ... columns.
So, I would like to know how to always returns a value from people.id even if for example people.id is not same as say .. income.id
Just change your joins to LEFT JOIN which return all the records from the LEFT table and only the matching from the RIGHT tables :
SELECT
`people`.`id`
, `people`.`name`
, `places`.`place_type`
, `places`.`aread`
, `family`.`family_count`
, `income`.`income_value`
, `income`.`average`
, `employment`.`address`
, `employment`.`duration`
FROM
`people`
LEFT JOIN `places`
ON (`people`.`id` = `places`.`id`)
LEFT JOIN `family`
ON (`people`.`id` = `family`.`id`)
LEFT JOIN `income`
ON (`people`.`id` = `income`.`id`)
LEFT JOIN `employment`
ON (`people`.`id` = `employment`.`id`) WHERE `people`.`full_name` = ? LIMIT 1
EDIT: If you want to know which tables didn't have a match, just search for null values. When left joining, the tables that didn't match the condition will get NULL values on their column selection.
Replace LEFT JOIN with INNER JOIN.
SELECT
`people`.`id`
, `people`.`name`
, `places`.`place_type`
, `places`.`aread`
, `family`.`family_count`
, `income`.`income_value`
, `income`.`average`
, `employment`.`address`
, `employment`.`duration`
FROM
`people`
LEFT JOIN `places`
ON (`people`.`id` = `places`.`id`)
LEFT JOIN `family`
ON (`people`.`id` = `family`.`id`)
LEFT JOIN `income`
ON (`people`.`id` = `income`.`id`)
LEFT JOIN `employment`
ON (`people`.`id` = `employment`.`id`) WHERE `people`.`full_name` = ? LIMIT 1

Using JOIN sql query

I would like to use JOIN instead of IN in the following SQL query. I can't figure out how to do it.
SELECT * FROM shop_orders WHERE
id IN (SELECT orders_id FROM shop_orders_data WHERE closed='1' /*AND backorder='0'*/ AND exhibition_id='389' AND
exhibition_id IN (SELECT id FROM shop_exhibitions WHERE
country_id IN (SELECT id FROM countries WHERE id='72')) AND in_country = '72' AND
exhibition_id IN (SELECT id FROM shop_exhibitions WHERE start<=1336946400 AND end>1336600800)) AND
id IN (SELECT orders_id FROM shop_orders_products WHERE
products_id IN (SELECT id FROM shop_products WHERE artno='120000' OR name LIKE '%120000%')) AND created>=1333231200 AND created<1333663200 ORDER BY created DESC
I tried this:
SELECT
s.*
FROM
shop_orders s
INNER JOIN shop_orders_data od ON s.id=od.orders_id
INNER JOIN shop_exhibitions se ON od.exhibition_id=se.id
INNER JOIN countries co ON se.country_id=co.id
INNER JOIN shop_orders_products sop ON s.id=sop.orders_id
INNER JOIN shop_products sp
ON sop.products_id=sp.id
WHERE od.closed=1
AND ( sp.artno='120000' or sp.name LIKE '%120000%' )
AND ( od.exhibition_id='389')
AND ( od.in_country = '72')
AND ( se.start <=1336946400)
AND ( se.end >1336600800)
AND ( se.created>=1333231200)
AND ( se.created<1333663200)
ORDER BY `s`.`created` DESC
I this correct??
See if this works (and study the code to learn how it works):
SELECT *
FROM shop_orders so
JOIN shop_orders_data sod ON (
(so.id = sod.orders_id)
AND (sod.closed = '1')
/*AND (sod.backorder = '0') */
AND (sod.exhibition_id = '389')
AND (sod.in_country = '72')
)
JOIN shop_exhibitions se ON (
(sod.exhibition_id = se.id)
AND (se.start <= 1336946400)
AND (se.end > 1336600800)
)
JOIN countries c ON (
(se.country_id = c.id)
AND (c.id = '72')
)
JOIN shop_orders_products sop ON (
(so.id = sop.orders_id)
)
JOIN shop_products sp ON (
(sop.products_id = sp.id)
AND ((sp.artno='120000') OR (sp.name LIKE '%120000%'))
)
WHERE (so.created >= 1333231200) AND (so.created < 1333663200)
ORDER BY so.created DESC;
The join syntax works like this:
SELECT field1,field2,field3
FROM FirstTable
JOIN SecondTable ON (FirstTable.PrimaryKey = SecondTable.ForeignKey)
JOIN ThirdTable ON (FirstTable.PrimaryKey = ThirdTable.ForeignKey)
Try applying this approach to your query.

SQL with GROUP BY and ORDER BY

I am trying to display posts from a table grouped by certain meta values from another table, and ordered by other meta values or post id if "recent" order is selected.
The best I came up with is:
SELECT `posts`.`id_post`,
m1.value AS REGIUNE,
m2.value AS JUDET,
m3.value AS LOCALITATE,
MAX(`posts`.`id_post`) AS ORDERBY
FROM `posts`
INNER JOIN `posts_meta` m1
ON(`posts`.`id_post`=m1.`id_post`)
INNER JOIN `posts_meta` m2
ON(`posts`.`id_post`=m2.`id_post`)
INNER JOIN `posts_meta` m3
ON(`posts`.`id_post`=m3.`id_post`)
WHERE
`posts`.`type` = 'published'
AND ( m1.`meta` = 'regiune' )
AND ( m2.`meta` = 'judet' )
AND ( m3.`meta` = 'localitate' )
GROUP BY posts.id_post
ORDER BY ORDERBY DESC
This however only works if we are not grouping by any meta value (m1.value, m2.value or m3.value).
This one should work...
SELECT `posts`.`id_post`,
m1.value AS REGIUNE,
m2.value AS JUDET,
m3.value AS LOCALITATE,
MAX(`posts`.`id_post`) AS ORDERBY
FROM `posts`
INNER JOIN `posts_meta` m1
ON(`posts`.`id_post`=m1.`id_post`)
INNER JOIN `posts_meta` m2
ON(`posts`.`id_post`=m2.`id_post`)
INNER JOIN `posts_meta` m3
ON(`posts`.`id_post`=m3.`id_post`)
WHERE
`posts`.`type` = 'published'
AND ( m1.`meta` = 'regiune' )
AND ( m2.`meta` = 'judet' )
AND ( m3.`meta` = 'localitate' )
GROUP BY 1,2,3,4
ORDER BY `posts`.`id_post` DESC

optimize this query

ms sql server 2008
SELECT Action.*
FROM Mailing
INNER JOIN ActionCategoryMailingBunch
ON Mailing.MailingID = ActionCategoryMailingBunch.MailingID
INNER JOIN ActionCategory
ON ActionCategoryMailingBunch.ActionCategoryID =
ActionCategory.ActionCategoryID
INNER JOIN Action
ON ActionCategory.ActionCategoryID = Action.ActionCategoryID
WHERE ( Mailing.MailingID = 7 )
AND ( Mailing.MailingID NOT IN (SELECT MailingID
FROM MailingReport) )
AND ( Action.ActionID NOT IN (SELECT ActionID
FROM MailingReport) )
AND ( ActionCategoryMailingBunch.MailingBunchStatusID = 4 )
especially this block
(Mailing.MailingID NOT IN (SELECT MailingID FROM MailingReport))
AND (Action.ActionID NOT IN (SELECT ActionID FROM MailingReport))
Add the below code in the select statement
Left Join MailingReport MR on MR.ActionID = Mailing.MailingID
Add the below code in Where clause
(MR.ActionID is null)
Performance upgrade due to following block
(Mailing.MailingID NOT IN (SELECT MailingID FROM MailingReport))
Final Query
SELECT Action.*
FROM Mailing
INNER JOIN ActionCategoryMailingBunch
ON Mailing.MailingID = ActionCategoryMailingBunch.MailingID
INNER JOIN ActionCategory
ON ActionCategoryMailingBunch.ActionCategoryID =
ActionCategory.ActionCategoryID
INNER JOIN Action
ON ActionCategory.ActionCategoryID = Action.ActionCategoryID
Left Join MailingReport MR on MR.ActionID = Mailing.MailingID
WHERE ( Mailing.MailingID = 7 )
--AND ( Mailing.MailingID NOT IN (SELECT MailingID
-- FROM MailingReport) )
AND
(MR.ActionID is null)
AND ( Action.ActionID NOT IN (SELECT ActionID
FROM MailingReport) )
AND ( ActionCategoryMailingBunch.MailingBunchStatusID = 4 )
Similarly you can do for the second block
Performance due to second block
AND (Action.ActionID NOT IN (SELECT ActionID FROM MailingReport))
Final Query for both blocks
SELECT Action.*
FROM Mailing
INNER JOIN ActionCategoryMailingBunch
ON Mailing.MailingID = ActionCategoryMailingBunch.MailingID
INNER JOIN ActionCategory
ON ActionCategoryMailingBunch.ActionCategoryID =
ActionCategory.ActionCategoryID
INNER JOIN Action
ON ActionCategory.ActionCategoryID = Action.ActionCategoryID
Left Join MailingReport MR on MR.ActionID = Mailing.MailingID
Left Join MailingReport MRA on MRA.ActionID = Action.ActionID
WHERE ( Mailing.MailingID = 7 )
AND
(MR.ActionID is null)
AND
(MRA.ActionID is null)
AND ( ActionCategoryMailingBunch.MailingBunchStatusID = 4 )