基于多对多关系匹配相似实体

new*_*ewb 6 sql t-sql sql-server

我的数据库中有两个与多对多关系连接的实体.我想知道列出哪些实体最相似的最佳方法是什么?

我尝试使用intersect进行count(*),但查询花费的时间太长,无法在我的数据库中的每个条目上运行(大约有20k条记录).运行我写的查询时,CPU使用率跳至100%,数据库出现锁定问题.

这是一些显示我尝试过的代码:

我的表格看起来像这样:

/* 20k records */
create table Movie(
   Id INT PRIMARY KEY,
   Title varchar(255)
);

/* 200-300 records */
create table Tags(
   Id INT PRIMARY KEY,
   Desc varchar(255)
);

/* 200,000-300,000 records */
create table TagMovies(
    Movie_Id INT,
    Tag_Id INT,
    PRIMARY KEY (Movie_Id, Tag_Id),
    FOREIGN KEY (Movie_Id) REFERENCES Movie(Id),
    FOREIGN KEY (Tag_Id) REFERENCES Tags(Id),
);
Run Code Online (Sandbox Code Playgroud)

(这是有效的,但速度非常慢)这是我编写的用于尝试列出它们的查询:通常我也会使用top 1过滤并添加where子句来获取一组特定的相关数据.

SELECT 
    bk.Id,
    rh.Id
FROM
    Movies bk
    CROSS APPLY (
        SELECT TOP 15
           b.Id,
           /* Tags Score */
           (
            SELECT COUNT(*) FROM (
                SELECT x.Tag_Id FROM TagMovies x WHERE x.Movie_Id = bk.Id
                INTERSECT
                SELECT x.Tag_Id FROM TagMovies x WHERE x.Movie_Id = b.Id
                ) Q1
           )
           as Amount
        FROM 
            Movies b 
        WHERE 
            b.Id <> bk.Id
        ORDER BY Amount DESC
    ) rh
Run Code Online (Sandbox Code Playgroud)

说明:电影有标签,用户可以尝试根据具有相似标签的其他电影找到类似于他们所选电影的电影.

bar*_*rat 4

嗯...只是一个想法,但也许我不明白...此查询应该按给定电影 ID 的标签返回最匹配的电影:

SELECT m.id, m.title, GROUP_CONCAT(DISTINCT t.Descr SEPARATOR ', ') as tags, count(*) as matches
FROM stack.Movie m 
LEFT JOIN stack.TagMovies tm ON m.Id = tm.Movie_Id
LEFT JOIN stack.Tags t ON tm.Tag_Id = t.Id
WHERE m.id != 1
AND tm.Tag_Id IN (SELECT Tag_Id FROM stack.TagMovies tm WHERE tm.Movie_Id = 1)
GROUP BY m.id
ORDER BY matches DESC
LIMIT 15;
Run Code Online (Sandbox Code Playgroud)

编辑:我刚刚意识到它是针对 M$ SQL 的...但也许可以做类似的事情...