Let us assume that we have two MySQL tables.
master
id | master | meta
1 | 78564 | 2,3,4
2 | 89567 | 1,3
3 | 45782 | 2,1,4
and metadata
id | buyer_id | platform
1 | 25 | mobile
2 | 35 | web
3 | 25 | web
4 | 17 | api
I need to get an array of buyer_ids and platforms when I give the master name. The master column is a unique index and the id of metadata is also a unique index. I want something like:
SELECT buyer_id, platform FROM metadata WHERE id IN (SELECT meta FROM
master WHERE master = '89567')
The above query doesn't work because the sub query returns a string. I need someway to convert that sub query result into a SET. I am currently using PHP to do it.
<?php $sql="SELECT meta FROM master WHERE master = '89567'";
$result = $connection->query($sql);
$result = $result->fetch_assoc();
$meta = $result['meta'];
$sql="SELECT buyer_id, platform FROM metadata WHERE id IN (".$meta.")";
$result = $connection->query($sql);?>
I am getting the required result but I want to optimize it. I want the whole thing to be done in single query using a sub query or a JOIN.
Background Story : I first used only one table to store all the data. It was serialized too. I did not use any indexes and the execution time was 0.290010929.
I then used non unique index for master column of master table. I was still using only one table and the execution time was 0.0186100006.
I then split the table into two with one unique index per each table as I explained above. I am using the above PHP code and the execution time is 0.0011548995.
I am sure that I can bring the execution time down to 0.0005 if you can answer my question. I am doing this for a very high traffic RESTful api. I want to optimize it to my best. Please help me.
Update : Thanks to @RiggsFolly.
I changed the tables' structure.
master
id | master(unique index)
1 | 78564
2 | 89567
3 | 45782
and metadata
id | master_id | buyer_id | platform
1 | 2 | 25 | mobile
2 | 3 | 25 | mobile
3 | 1 | 35 | web
4 | 3 | 35 | web
5 | 1 | 25 | web
6 | 2 | 25 | web
7 | 1 | 17 | api
8 | 3 | 17 | api
master_id is a non unique index.
Now, my query is
SELECT buyer_id, platform FROM metadata WHERE master_id = (SELECT id FROM master WHERE
master = '89567')
and the execution time is 0.00079298019.
I do not think the execution time would be lesser even if I could convert a string into SET. But, I still want to know the answer to my question.
Keep a pre-computed table using a trigger.
create table master_metadata(
masterid bigint(10),
metaid bigint(10)
);
Your query, then, should be:
SELECT buyer_id, platform
FROM metadata
WHERE id IN(
SELECT metaid
FROM master_metadata
WHERE masterid = '89567'
);
The code that would mantain this table follows.
drop procedure if exists sp_tr_master_insert_update;
drop trigger if exists tr_master_insert;
drop trigger if exists tr_master_update;
delimiter //
create
definer=root@localhost
procedure sp_tr_master_insert_update(
in _masterid bigint(10)
)
modifies sql data
reads sql data
begin
declare metaids varchar(255);
--
declare commapos int;
declare metaid varchar(255);
-- -------------------------------------------------------------------------
delete from master_metadata
where masterid = _masterid;
-- -------------------------------------------------------------------------
set metaids =(
select meta
from master
where master = _masterid
);
if coalesce(metaids, '') <> '' then
_split: LOOP
set commapos = locate(',', metaids);
if commapos = 0 then
insert into master_metadata
values(_masterid, metaids);
leave _split;
else
set metaid = left(metaids, commapos - 1);
set metaids = right(metaids, length(metaids) - commapos);
insert into master_metadata
values(_masterid, metaid);
end if;
END LOOP _split;
end if;
end //
CREATE DEFINER=root@localhost TRIGGER tr_master_insert
AFTER insert ON master
FOR EACH ROW
BEGIN
CALL sp_tr_master_insert_update(NEW.master);
END//
CREATE DEFINER=root@localhost TRIGGER tr_master_update
AFTER update ON master
FOR EACH ROW
BEGIN
CALL sp_tr_master_insert_update(NEW.master);
END//
delimiter ;
Index creation and other performance tweaks is up to you.
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.