mySQL:是否可以更快地进行此查询?

Bus*_*icK 7 mysql sql optimization query-optimization

我有一个包含数百万条目的表"test".每行包含一个浮点"特征"和一个"计数"这个特征在项目"id"中出现的频率.该表的主键是"id"和"feature"的组合,即每个项目可能具有多个功能.每个商品ID通常有几百到几千个要素条目.

create table test 
(
    id      int not null,
    feature double not null,
    count   int not null
);
Run Code Online (Sandbox Code Playgroud)

任务是找到给定参考项目的500个最相似的项目.相似性以两个项目中相同特征值的数量来度量.我提出的查询在下面引用,但尽管正确使用索引,其执行计划仍包含"using temporary"和"using filesort",为我的用例提供了不可接受的性能.

select 
    t1.id,
    t2.id,
    sum( least( t1.count, t2.count )) as priority 
from test as t1
inner join test as t2 
     on t2.feature = t1.feature
where t1.id = {some user supplied id value} 
group by t1.id, t2.id 
order by priority desc
limit 500;
Run Code Online (Sandbox Code Playgroud)

关于如何改进的任何想法?可以修改模式并根据需要添加索引.

Qua*_*noi 4

在当前模式下,此查询几乎无法改进。

您已经有了一个索引feature,这是您使用当前模式设计可以做的最好的事情。

这个问题比不是顺序关系更相似。如果比a更相似,并不意味着比更不相似。因此,您无法构建描述这种关系的单个索引,并且需要分别为每个项目执行此操作,这将使您的索引条目很长,其中是项目数。bccabN^2N

如果您始终只需要顶部500项目,则可以将索引限制为该数字(在这种情况下它将保存500 * N条目)。

MySQL不支持索引或物化视图,因此您必须自己执行此操作:

  1. 创建一个像这样的表:

    CREATE TABLE similarity
            (
            id1 INT NOT NULL,
            id2 INT NOT NULL,
            similarity DOUBLE NOT NULL,
            PRIMARY KEY (id1, id2),
            KEY (id1, similarity)
            )
    
    Run Code Online (Sandbox Code Playgroud)
  2. 每当您将新功能插入表中时,都会反映以下更改similarity

    INSERT
    INTO    similarity
    SELECT  @newid, id,
            LEAST(@newcount, count) AS ns
    FROM    test
    WHERE   feature = @newfeature
            AND id <> @newid
    ON DUPLICATE KEY UPDATE
    SET     similarity = similarity + ns;
    
    
    INSERT
    INTO    similarity
    SELECT  @newid, id,
            LEAST(@newcount, count) AS ns
    FROM    test
    WHERE   feature = @newfeature
            AND id <> @newid
    ON DUPLICATE KEY UPDATE
    SET     similarity = similarity + ns;
    
    Run Code Online (Sandbox Code Playgroud)
  3. 及时删除多余的相似之处:

    DELETE  s
    FROM    (
            SELECT  id1,
                    (
                    SELECT  similarity
                    FROM    similarity si
                    WHERE   si.id1 = s.id1
                    ORDER BY
                            si.id1 DESC, si.similarity DESC
                    LIMIT 499, 1
                    ) AS cs
            FROM    (
                    SELECT  DISTINCT id1
                    FROM    similarity
                    ) s
            ) q
    JOIN    similarity s
    ON      s.id1 = q.id1
            AND s.similarity < q.cs
    
    Run Code Online (Sandbox Code Playgroud)
  4. 查询您的数据:

    SELECT  id2
    FROM    similarity
    WHERE   id1 = @myid
    ORDER BY
            similarity DESC
    LIMIT 500
    
    Run Code Online (Sandbox Code Playgroud)