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)
关于如何改进的任何想法?可以修改模式并根据需要添加索引.
在当前模式下,此查询几乎无法改进。
您已经有了一个索引feature,这是您使用当前模式设计可以做的最好的事情。
这个问题比不是顺序关系更相似。如果比a更相似,并不意味着比更不相似。因此,您无法构建描述这种关系的单个索引,并且需要分别为每个项目执行此操作,这将使您的索引条目很长,其中是项目数。bccabN^2N
如果您始终只需要顶部500项目,则可以将索引限制为该数字(在这种情况下它将保存500 * N条目)。
MySQL不支持索引或物化视图,因此您必须自己执行此操作:
创建一个像这样的表:
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)每当您将新功能插入表中时,都会反映以下更改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)及时删除多余的相似之处:
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)查询您的数据:
SELECT id2
FROM similarity
WHERE id1 = @myid
ORDER BY
similarity DESC
LIMIT 500
Run Code Online (Sandbox Code Playgroud)