改善非常慢的相关项目的最佳选择'查询

时间:2017-04-25 02:30:00

标签: mysql sql

我有两个表,一个是图像,另一个是描述哪些用户喜欢哪些图像。第二个表每个图像/用户组合只有一行。我想编写一个查询,该查询将返回数据库中的其他图像中有多少人喜欢'尽可能共同。因此,表格如下:

images
+----+----------+
| id | filename |
+----+----------+

images_users
+----------+---------+
| image_id | user_id |
+----------+---------+

我的查询是:

SELECT images.filename FROM 
  images_users INNER JOIN images ON images.id = images_users.image_id 
   WHERE images_users.user_id IN ( .... list of user IDs ....) 
   AND NOT images.id = <current image id>
  GROUP BY images.id ORDER BY COUNT(images.id) DESC LIMIT 10;

也就是说,查找匹配&#39; likers&#39;的所有行,按图片ID分组,按其计数顺序,并返回前10名。我还排除当前图片ID,因为当然这总是最受欢迎的。

当我想要匹配的用户ID列表增长时,此查询可能需要几分钟才能运行 - 尽管我只在家用PC上运行它,而不是大型服务器。

我有点感觉我被困在这里,因为我的数据根据​​规则进行了规范化,但对于服务器而言,这只是一项艰巨的工作。我有连接中的所有列和查询的索引。

我可以用其他方式表示此信息,这可能会缩短查询时间吗?

-----编辑以下问题-----

查询的解释输出如下:

explain SELECT filename  from images_users inner join images on id = image_id 
where image_users.user_id in
(162,591,596,603,856,1654,1967,2219,3640,3847,3956,9201,10601) 
and not images.image_id = 41578 group by images.id order by count(images.id) desc limit 10;

"1" "SIMPLE"    "images_users"  "range" "u_id_2,u_id,i_id"  "i_id"  "4" \N  "9086346"   "Using where; Using temporary; Using filesort"
"1" "SIMPLE"    "images"    "eq_ref"    "PRIMARY"   "PRIMARY"   "4" "images_users.i_id" "1" ""

images_users表中大约有10,000个用户,大约1.5M图像和大约6M行。

1 个答案:

答案 0 :(得分:0)

图表数据库是答案

我在这里回答了我自己的问题,因为我接受了@Jason的评论,跟着neo4j的链接,安装了它,学到了一些优秀的查询语言Cyper和bam。问题解决了。

我拿走了所有数据,200万张图片和1000万张关系,并将它们推入neo4j。首先,我创建了索引。

CREATE INDEX ON :Image(filename)
CREATE INDEX ON :User(name)

然后针对用户和图像之间的每个关系运行以下查询。如果它们不存在,这也会为用户和图像创建节点。

MERGE (i:Image{filename:'...'})
MERGE (u:User{name:'...'})
CREATE (u)-[:LIKES]->(i)

这有点慢,我确实最终改进了导入过程,但结果数据是一样的。然后搜索查询变为

MATCH (n:Image{filename:'...'})<-[]-(u:User)-[l]->(i:Image) 
WITH count(l) AS c, i.filename AS f 
ORDER BY c DESC LIMIT 10

在任何情况下,这是一种更具表现力的编写查询的方式,并且比同等的MySQL查询运行速度快一个数量级,在该查询中存在所有适当的索引。

其他查询,也可能最终成为非常昂贵的联接,比如向我展示超过五个喜欢的所有图像,非常有效

MATCH (n:Image) where size ( (n)<-[]-() ) > 3 return n.filename 
LIMIT 20