简体   繁体   English

如何将逗号分隔的字符串转换为SET以在MySQL的另一个查询中使用?

[英]How to convert a comma separated string into a SET to use in another query in MySQL?

Let us assume that we have two MySQL tables. 让我们假设我们有两个MySQL表。
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. 输入主名称时,我需要获取buyer_id和平台的数组。 The master column is a unique index and the id of metadata is also a unique index. 主列是唯一索引,元数据的id也是唯一索引。 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. 我需要某种方式将该子查询结果转换为SET。 I am currently using PHP to do it. 我目前正在使用PHP来做到这一点。

<?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. 我希望使用子查询或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. 我没有使用任何索引,执行时间为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. 我仍然只使用一个表,执行时间为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. 我正在使用上面的PHP代码,执行时间为0.0011548995。

I am sure that I can bring the execution time down to 0.0005 if you can answer my question. 我敢肯定,如果您可以回答我的问题,我可以将执行时间减少到0.0005。 I am doing this for a very high traffic RESTful api. 我这样做是针对流量非常高的RESTful API。 I want to optimize it to my best. 我想将其最佳化。 Please help me. 请帮我。

Update : Thanks to @RiggsFolly. 更新 :感谢@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. master_id是非唯一索引。
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. 执行时间为0.00079298019。
I do not think the execution time would be lesser even if I could convert a string into SET. 我认为即使将字符串转换为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. 索引创建和其他性能调整取决于您。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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