简体   繁体   中英

Any way to do this query faster with big data

This query takes around 2.23seconds and feels a bit slow ... is there anyway to make it faster. our member.id, member_id, membership_id, valid_to, valid_from has index as well.

select * 
from member 
where (member.id in ( select member_id from member_membership mm 
INNER JOIN membership m ON mm.membership_id = m.id 
where instr(organization_chain, 2513) and m.valid_to > NOW() and m.valid_from < NOW() ) ) 
order by id desc 
limit 10 offset 0

EXPLAIN FOR WHAT QUERY DOING: every member has many a member_memberships and and member_memberships connect with another table called membership there we have the membership details. so query will get all members that has valid memberships and where the organization id 2513 exist on member_membership. Tables as following:

CREATE TABLE `member` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `first_name` varchar(255) DEFAULT NULL,
  `last_name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;

CREATE TABLE `member_membership` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `membership_id` int(11) DEFAULT NULL,
  `member_id` int(11) DEFAULT NULL,
  `organization_chain` text DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `member_membership_to_membership` (`membership_id`),
  KEY `member_membership_to_member` (`member_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;

CREATE TABLE `membership` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `valid_to` datetime DEFAULT NULL,
  `valid_from` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `valid_to` (`valid_to`),
  KEY `valid_from` (`valid_from`),
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;

ALTER TABLE `member_membership` ADD CONSTRAINT `member_membership_to_membership` FOREIGN KEY (`membership_id`) REFERENCES `membership` (`id`);

ALTER TABLE `member_membership` ADD CONSTRAINT `member_membership_to_member` FOREIGN KEY (`member_id`) REFERENCES `member` (`id`);

Here with EXPLAIN statement => https://i.ibb.co/xjrcYWR/EXPLAIN.png

Relations

  • member has many member_membership
  • membership has manymember_membership
  • So member_membership is like join for tables member and membership.

Well I found a way to make it less to 800ms ... like this. Is this good way or maybe there is more we can do?

select * 
from member  
where (member.id in ( select member_id from member_membership mm FORCE INDEX (PRIMARY)
INNER JOIN membership m ON mm.membership_id = m.id  
where instr(organization_chain, 2513) and m.valid_to > NOW() and m.valid_from < NOW() ) ) 
order by id desc 
limit 10 offset 0

NEW UPDATE.. and I think this solve the issue.. 15ms :) I added FORCE INDEX.. The FORCE INDEX hint acts like USE INDEX (index_list), with the addition that a table scan is assumed to be very expensive. In other words, a table scan is used only if there is no way to use one of the named indexes to find rows in the table.

 select * 
from member  
where (member.id in ( select member_id from member_membership mm FORCE INDEX (member_membership_to_member)
INNER JOIN membership m FORCE INDEX (organization_to_membership) ON mm.membership_id = m.id  
where instr(organization_chain, 2513) and m.valid_to > NOW() and m.valid_from < NOW() ) ) 
order by id desc 
limit 10 offset 0

How big is organization_chain ? If you don't need TEXT , use a reasonably sized VARCHAR so that it could be in an index. Better yet, is there some way to get 2513 in a column by itself?

Don't use id int(11) NOT NULL AUTO_INCREMENT, in a many-to-many table; rather have the two columns in PRIMARY KEY .

Put the ORDER BY and LIMIT in the subquery.

Don't use IN ( SELECT ...) , use a JOIN .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM