index_merge full table scan - 2 seconds mysql select - mysql

I have this select:
SELECT MAX(id) FROM chat
WHERE (`to` = 1 and `del_to_status` = '0') or (`from` = 1 and `del_from_status` = '0')
GROUP BY CASE WHEN 1 = `to` THEN `from` ELSE `to` END
chat:
`chat` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`from` int(11) UNSIGNED NOT NULL,
`to` int(11) UNSIGNED NOT NULL,
`message` text NOT NULL,
`del_from_status` tinyint(1) NOT NULL DEFAULT '0',
`del_to_status` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `from` (`from`),
KEY `to` (`to`),
);
The problem is it is using full table scan:
it is taking a lot of time. any ideas to get faster results?

What do you think about this solution:
select grouped_by_to.user, greatest(grouped_by_to.id, grouped_by_from.id ) from
(
select c1.to as user, max(id) as id from chat c1
group by c1.to
) grouped_by_to
join
(
select c1.from as user, max(id) as id from chat c1
group by c1.from
) grouped_by_from on grouped_by_from.user = grouped_by_to.user
Note that i ignored the del_to_status columns, you can add them easily.
But actually I think your whole db schema is wrong, I think you need something more like :
`messages` (
`message_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` int(11) UNSIGNED NOT NULL,
`message` text NOT NULL,
`message_date` timestamp NOT NULL,
PRIMARY KEY (`message_id`),
);
`conversatinos` (
`conversation_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`message_id` int(11) UNSIGNED NOT NULL,
PRIMARY KEY (`conversation_id`),
);
`users` (
`user_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`user_name` int(11) UNSIGNED NOT NULL,
PRIMARY KEY (`user_id`),
);
AND maybe if you need:
`chat` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`message_id` int(11) UNSIGNED NOT NULL,
PRIMARY KEY (`id`),
);

Related

Mysql selecting user friendes likes

i have these tables
posts table
CREATE TABLE `users_posts` (
`pid` INT(11) NOT NULL AUTO_INCREMENT, /*post id*/
`uid` INT(11) NOT NULL, /*user who created the post, owner*/
`created_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_date` DATETIME NOT NULL,
`post_status` TINYINT(1) NOT NULL,
`content` TEXT NULL COLLATE 'utf8_general_ci',
PRIMARY KEY (`pid`),
)
connections table
CREATE TABLE `users_connections` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`user_1_uid` INT(11) NOT NULL, /*user id*/
`user_2_uid` INT(11) NOT NULL, /*friend user id of user id*/
`connections_status` TINYINT(4) NOT NULL,
PRIMARY KEY (`id`)
)
likes table
CREATE TABLE `post_ups` (
`upid` INT(11) NOT NULL AUTO_INCREMENT,
`uid` INT(11) NOT NULL, /*user id who like the post*/
`puid` INT(11) NOT NULL, /*post owner user id=users_posts.uid*/
`pid` INT(11) NOT NULL, /*post id=users_posts.pid*/
`up_status` TINYINT(1) NOT NULL,
PRIMARY KEY (`upid`),
INDEX `uid` (`uid`),
INDEX `up_status` (`up_status`),
INDEX `pid` (`pid`)
)
i need to select all posts and inside the query i need to check if some of my friend has like the post i'm currently selecting and if true , i can show this post on top of other post to show more relevant content
SELECT *,IF(CHECK IF FREIND LIKED THIS POST PUID == F_UID) FROM users_posts
is this possible ??
Query must like below:
SELECT up.*,
(SELECT count(*) FROM post_ups pups
WHERE up.pid=pups.pid AND up.uid <> pups.uid/*exclude own like*/
AND EXISTS (SELECT 0 FROM users_connections uc
WHERE uc.user_1_uid=up.uid/*pups.puid*/ AND uc.user_2_uid=pups.uid)) relevance
FROM users_posts up
ORDER BY relevance DESC;

MYSQL: Left Join is very slow

I'm using MySQl for my database and I have three tables where I want to join them using left join but the performance are very slow.
Below are the tables:
CREATE TABLE IF NOT EXISTS `register_doctor` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`doc_title` int(11) NOT NULL,
`first_name` varchar(35) NOT NULL,
`last_name` varchar(35) DEFAULT NULL,
`gender` int(11) NOT NULL,
`city_id` int(11) NOT NULL,
`province_id` int(11) NOT NULL,
`specialty_id` int(11) NOT NULL,
`status` int(11) NOT NULL COMMENT '0 = Pending; 1 = Verified, 2 = Not Reg Yet, 3 = Pending Approval',
`str_number` char(6) DEFAULT NULL,
`editted_by` int(11) DEFAULT NULL,
`editted_date` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `city_id` (`city_id`),
KEY `specialty_id` (`specialty_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=10267 ;
CREATE TABLE IF NOT EXISTS `ref_doctor_practice_place` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`doctor_id` int(11) NOT NULL,
`practice_place_id` int(11) NOT NULL,
`is_primary` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `doctor_id_2` (`doctor_id`,`practice_place_id`),
KEY `doctor_id` (`doctor_id`),
KEY `practice_place_id` (`practice_place_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=23677 ;
CREATE TABLE IF NOT EXISTS `practice_place` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(75) NOT NULL,
`statement` text,
`address` varchar(200) NOT NULL,
`phone` varchar(15) NOT NULL,
`fax` varchar(15) NOT NULL,
`email` varchar(50) NOT NULL,
`village_id` varchar(50) NOT NULL,
`sub_district_id` varchar(50) NOT NULL,
`province_id` varchar(50) NOT NULL,
`zipcode` varchar(10) NOT NULL,
`website` varchar(50) NOT NULL,
`latitude` double NOT NULL,
`longitude` double NOT NULL,
`type` int(11) NOT NULL,
`managed_by` int(11) DEFAULT '0',
`doctor_group_id` int(11) NOT NULL,
`category` varchar(50) NOT NULL,
`photo_file` char(36) NOT NULL,
`is_branch` int(11) NOT NULL,
`parent_id` int(11) NOT NULL,
`editted_by` int(11) NOT NULL,
`editted_date` bigint(20) NOT NULL,
`status` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `village_id` (`village_id`),
KEY `doctor_group_id` (`doctor_group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=24182 ;
My query is like this:
SELECT SQL_CALC_FOUND_ROWS RD.id as rd_id
, RD.first_name
, RD.last_name
, RD.gender
, RD.str_number
, GROUP_CONCAT(DISTINCT PP.type SEPARATOR '|') as pp_type
FROM register_doctor RD
LEFT
JOIN ref_doctor_practice_place RDPP
ON RDPP.doctor_id = RD.id
LEFT
JOIN practice_place PP
ON PP.id = RDPP.practice_place_id
GROUP
BY RD.id
ORDER
BY RD.id DESC
LIMIT 0,25
Can anyone help me about this? Many thanks.
As requested by Strawberry, here I put the result of using EXPLAIN:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE RD index PRIMARY,city_id PRIMARY 4 NULL 15 NULL
1 SIMPLE RDPP ref doctor_id doctor_id 4 k6064619_lokadok.RD.id 1 NULL
1 SIMPLE PP eq_ref PRIMARY,id PRIMARY 4 k6064619_lokadok.RDPP.practice_place_id 1 NULL
I'm sorry guys. I should have posted the real query. The left join acutally is like this:
LEFT JOIN ref_doctor_practice_place RDPP ON **ABS(RDPP.doctor_id) = RD.id**
I thought the ABS didn't really matter so I erase it to make it more straight forward. But actually this is the culprit.
Nothing wrong with my query. So case close. Thanks for any attempt to help me. Appreciate it.

How to optimize this heavy MySQL query?

I need to optimize a MySQL query which takes a lot of time to load.
Here it is :
SELECT
p.id,
UNIX_TIMESTAMP(p.last_answer_date) AS last_answer_date_timestamp,
p.sender_id,
p.recipient_id,
p.is_read_sender,
p.last_answer_user_id,
p.is_read_recipient,
(SELECT m.read FROM pm_message m WHERE m.conv_id = p.id AND m.user_id != $user_id ORDER BY m.date DESC LIMIT 1) AS read_status,
(SELECT m.content FROM pm_message m WHERE m.conv_id = p.id ORDER BY m.date DESC LIMIT 1) AS last_message,
(SELECT u.username FROM user u WHERE (u.id = p.sender_id OR u.id = p.recipient_id) AND u.id != $user_id LIMIT 1) AS from_username,
(SELECT u.id FROM user u WHERE (u.id = p.sender_id OR u.id = p.recipient_id) AND u.id != $user_id LIMIT 1) AS from_userid,
(SELECT ui.gender FROM user_info ui WHERE (ui.user_id = p.sender_id OR ui.user_id = p.recipient_id) AND ui.user_id != $user_id LIMIT 1) AS from_gender,
(SELECT ph.thumb_url FROM photo ph, user_info ui WHERE ui.main_photo = ph.id AND (ph.user_id = p.sender_id OR ph.user_id = p.recipient_id) AND ph.user_id != $user_id LIMIT 1) AS from_thumb_url
FROM pm_conv p
WHERE p.sender_id = $user_id OR p.recipient_id = $user_id
ORDER BY p.last_answer_date DESC LIMIT 25;
This query gets me the result I want but it's really slow... And I think that the nested selects is the reason why this query is so slow.
Here are the tables structures for this query :
CREATE TABLE IF NOT EXISTS `photo` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`url` varchar(255) DEFAULT NULL,
`thumb_url` varchar(255) DEFAULT NULL,
`user_id` int(11) NOT NULL,
`date` datetime NOT NULL,
`status` int(11) NOT NULL,
`votes` int(11) DEFAULT '0',
`comments` int(11) DEFAULT '0',
`views` int(11) DEFAULT '0',
`text` text,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `pm_conv` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` datetime NOT NULL,
`sender_id` int(11) NOT NULL,
`recipient_id` int(11) NOT NULL,
`last_answer_date` datetime NOT NULL,
`nb_messages` int(11) NOT NULL,
`is_read_sender` int(11) NOT NULL,
`is_read_recipient` int(11) NOT NULL DEFAULT '0',
`last_answer_user_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `recipient_id` (`recipient_id`),
KEY `sender_id` (`sender_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `pm_message` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` datetime NOT NULL,
`content` text NOT NULL,
`user_id` int(11) NOT NULL,
`conv_id` int(11) NOT NULL,
`read` int(11) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `conv_id` (`conv_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `user` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`encrypt_id` varchar(255) DEFAULT NULL,
`register_date` datetime DEFAULT NULL,
`last_login_date` datetime DEFAULT NULL,
`username` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`banned` int(11) DEFAULT NULL,
`banned_reason` text,
`first_step_form` int(11) DEFAULT '0',
`status` int(11) DEFAULT NULL,
`valid_snapchat` int(11) DEFAULT '0',
`introduced_forum` int(11) DEFAULT '0',
`referer` varchar(255) DEFAULT NULL,
`allow_social_featuring` int(11) DEFAULT NULL,
`rank` int(11) DEFAULT NULL,
`fb_id` bigint(20) DEFAULT NULL,
`rate_app_status` int(11) DEFAULT NULL,
`last_activity_date` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `user_info` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`gender` int(11) DEFAULT NULL,
`birthday` date DEFAULT NULL,
`about` text,
`main_photo` int(11) DEFAULT NULL,
`country` varchar(100) DEFAULT NULL,
`city` varchar(100) DEFAULT NULL,
`relation_type` varchar(30) DEFAULT NULL,
`user_id` int(11) DEFAULT NULL,
`fb_link` varchar(255) DEFAULT NULL,
`twitter_link` varchar(255) DEFAULT NULL,
`youtube_link` varchar(255) DEFAULT NULL,
`instagram_link` varchar(255) DEFAULT NULL,
`app_pref_forum` int(11) DEFAULT NULL,
`app_pref_pm` int(11) DEFAULT NULL,
`app_pref_snapchat_request` int(11) DEFAULT NULL,
`browse_invisibly` int(11) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `main_photo` (`main_photo`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
Can someone help me to optimize this heavy query?
Thanks!
you can see in the explain plan some tables are being accessed by inefficient indexes. try to calculate statistics on all the tables to see if it changes something (using analyze table).
You can join user table in order to get username and id at once instead of having two subqueries, probably you can do the same with pm_message, but it's a little trickier since subqueries have different conditions.
I would also combine user and user_info tables into, as I can see they have one-to-one relation, so it doesn't makes sense to store this data in different tables. This would allow you to get rid off 4th subquery and simplify the 5th one.
In some cases it is better to perform several queries instead of one with subqueries.

sql can't figure out the query

I have three tables:
CREATE TABLE IF NOT EXISTS `contacts` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`providerId` int(10) unsigned NOT NULL DEFAULT '0',
`requestId` int(10) unsigned NOT NULL DEFAULT '0',
`status` binary(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
)
CREATE TABLE IF NOT EXISTS `messages` (
`id` int(255) NOT NULL AUTO_INCREMENT,
`fromuid` int(255) NOT NULL,
`touid` int(255) NOT NULL,
`sentdt` datetime NOT NULL,
`read` tinyint(1) NOT NULL DEFAULT '0',
`readdt` datetime DEFAULT NULL,
`messagetext` longtext CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
PRIMARY KEY (`id`),
KEY `id` (`id`)
)
CREATE TABLE IF NOT EXISTS `users` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`email` varchar(255) DEFAULT NULL,
`mobile` varchar(15) NOT NULL,
`password` varchar(255) NOT NULL,
`city` varchar(255) NOT NULL,
`zip` varchar(15) DEFAULT NULL,
`device` varchar(50) DEFAULT NULL,
`version` varchar(10) DEFAULT NULL,
`photo` varchar(255) DEFAULT NULL,
`created` datetime NOT NULL,
`live` enum('0','1') NOT NULL DEFAULT '1',
`authenticationTime` datetime NOT NULL,
`userKey` varchar(255) DEFAULT NULL,
`IP` varchar(50) DEFAULT NULL,
`port` int(10) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `firstname` (`mobile`,`city`,`zip`)
)
And this SQL query that finds out friends/contacts for specified user (user id 1 in this case):
SELECT u.id
,u.mobile
,u.name
,(NOW() - u.authenticationTime) AS authenticateTimeDifference
,u.IP
,f.providerid
,f.requestid
,f.status
,u.port
FROM contacts f
LEFT JOIN users u ON u.id =
IF (
f.providerid = 1
,f.requestid
,f.providerid
) WHERE (
f.providerid = 1
AND f.status = 1
)
OR f.requestid = 1
That works fine but I want to be able to also join messages table and show user's friends/contacts who have talked latest (meaning latest conversations first) with order by messages.sentdt desc option but I am unable to figure out how to do that, I tried all joins but none worked :(
Your help will be greatly appreciated. Thanks
Update
Here is sample data above query returns:
In that same resultset, I want to be able to sort based on order by messages.sentdt desc but I am not sure how to pull that in and sort resultset by latest message first
Try this:
select u.id
, u.mobile
, u.name
, (NOW() - u.authenticationTime) as authenticateTimeDifference
, u.IP
, f.providerid
, f.requestid
, f.status
, u.port
from contacts f
left join users u
on u.id = if (f.providerid = 1, f.requestid, f.providerid)
left join (select fromuid, max(sentdt) as sentdt from messages group by fromuid) m
on m.fromuid = if (f.providerid = 1, f.providerid, f.requestid)
where (f.providerid = 1 and f.status = 1)
or f.requestid = 1
order by m.sentdt

Need suggestion on optimization of MYSQL query

SELECT `tb1`.`id`
FROM `table1` as tb1
INNER JOIN `table2` as tb2 ON tb1.id = tb2.id
INNER JOIN `table3` as tb3 ON tb1.id = tb3.id
WHERE (tb1.item_id = '1')
AND (tb1.user_id = '20')
AND (tb1.type IN ('UPDATE1','UPDATE2','UPDATE3'))
AND (tb1.status = 'DELIVERED')
ORDER BY tb1.date DESC
LIMIT 100
CREATE TABLE `table1` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` INT(11) UNSIGNED NOT NULL,
`item_id` INT(11) UNSIGNED NULL DEFAULT NULL,
`source` ENUM('CPAS','UNIQUE_KEY','BILLING_PARTNER','GAME','MERCURY') NOT NULL,
`date` DATETIME NOT NULL,
`status` ENUM('PENDING','DELIVERED','FAILED','REFUNDED') NOT NULL,
`source_transaction_id` VARCHAR(127) NULL DEFAULT NULL,
`type` ENUM('UPDATE1','UPDATE2','UPDATE3','UPDATE4') NULL DEFAULT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `table2` (
`id_p` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`id` INT(11) UNSIGNED NOT NULL,
`amount` DECIMAL(18,2) NOT NULL,
`old_balance` DECIMAL(18,2) NULL DEFAULT NULL,
`description` VARCHAR(255) NULL DEFAULT NULL,
`date` DATETIME NULL DEFAULT NULL,
`wallet_currency_id` INT(11) NULL DEFAULT NULL,
`wallet_currency_code` VARCHAR(50) NULL DEFAULT NULL,
`wallet_currency_name` VARCHAR(100) NULL DEFAULT NULL,
`type` ENUM('GAIN','SPENT') NULL DEFAULT NULL,
PRIMARY KEY (`id_p`),
INDEX `id` (`id`)
)
CREATE TABLE `table3` (
`id_p` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`id` INT(11) UNSIGNED NOT NULL,
`amount` DECIMAL(18,2) NOT NULL,
`old_balance` DECIMAL(18,2) NULL DEFAULT NULL,
`description` VARCHAR(255) NULL DEFAULT NULL,
`date` DATETIME NULL DEFAULT NULL,
`wallet_currency_id` INT(11) NULL DEFAULT NULL,
`wallet_currency_code` VARCHAR(50) NULL DEFAULT NULL,
`wallet_currency_name` VARCHAR(100) NULL DEFAULT NULL,
`type` ENUM('GAIN','SPENT') NULL DEFAULT NULL,
PRIMARY KEY (`id_p`),
INDEX `id` (`id`)
)
What optimization possible on the above query.
table1 contains more than 500000 rows, table2 and table3 can also have more than 100000 rows.
As per query for particular player and game table1 can have more than 100000 rows.
Is the above query is ok for large large tables or should I split the query in multiple queries.
NDB Engine used.
Please suggest me possible optimization.
Thanks,
Shiv
See comments above, but, at a guess, an index on (item_id,user_id,type,status) might help.