2009-10-07 124 views
1

我正在编写一个PHP/MySQL网站,我想实现一个类似于stackoverflow标记引擎。我在DB 3个相关的表: 1.用品 2.标签 3. ItemTagMap(地图标记的项目,N:N映射)现在如何在php/mysql中实现类似SO的标记系统?

,搜索页面上我想显示所有的不同列表标记整个搜索结果(而不仅仅是当前页面),以便用户可以通过添加/删除标记列表中的标记来“精炼”他们的搜索。

问题是这是一个非常沉重的数据库查询,并且可能会有大量的搜索请求导致不同的结果集和不同的标签集。

有谁知道如何有效地实现这一点?

+1

在增加要求的风险下,是不是也很好地显示COUNT每个标签,对应一个特定的搜索? – mjv 2009-10-07 02:04:53

+0

是的,我会这样做 - 我甚至统计每个标签存储在单独的表中。 – 2009-10-07 02:11:25

回答

8

在我们进入提前优化模式之前,查看下面的查询模板可能很有用。如果没有其他可以用来作为衡量可能的优化效果的基线。

SELECT T.Tagid, TagInfo.TagName, COUNT(*) 
FROM Items I 
JOIN Tags TagInfo ON TagInfo.TagId = T.TagId 
JOIN ItemTagMap T ON I.ItemId = T.ItemId 
--JOIN ItemTagMap T1 ON I.ItemId = T1.ItemId 
WHERE I.ItemId IN 
    (
     SELECT ItemId 
     FROM Items 
     WHERE -- Some typical initial search criteria 
     Title LIKE 'Bug Report%' -- Or some fulltext filter instead... 
     AND ItemDate > '02/22/2008' 
     AND Status = 'C' 
) 
--AND T1.TagId = 'MySql' 
GROUP BY T.TagId, TagInfo.TagName 
ORDER BY COUNT(*) DESC 

子查询是“驱动查询”,即对应于最终用户的初始标准的那个。 (请参阅下面有关此查询的详细信息,需要多次才能适用于整体优化流程) 注释为T1上的JOIN(并且可能在选择多个标记时T2,T3),并且使用WHERE子句相关标准。当用户选择特定标签时,无论是作为初始搜索的一部分还是通过细化,都需要这些。 (这可能是更有效的放置这些连接,并且其中所述子查询中的条款;更多关于这些下文)

讨论... “驱动查询”,或其变体需要用于两个不同用途:

  • 1,以提供所需要枚举所有相关联的标签项目Id的完整列表。

  • 2提供前N个ItemId值(N是显示页面大小),用于在Item表中查找Item详细信息。

注意,完整列表不需要进行排序(或者也可以从不同的顺序排序中获益),从而使第二列表需要根据用户的选择进行排序(比如按日期,降序或标题,按字母顺序升序)。还要注意的是,如果需要任何排序顺序,查询的代价将意味着处理完整列表(由SQL本身避免奇怪的优化,和/或一些非规范化,SQL需要“查看”该列表上的最后记录,如果它们属于顶部,按照顺序)。

这后一个事实是赞成为两个目的有相同的查询,相应的列表可以存储在临时表中。一般流程是快速查找含有详细信息的前N个项目记录,并立即将其返回给应用程序。然后,应用程序可以获取ajax-fashion用于细化的标签列表。这个列表将产生一个类似于上面的查询,其中子查询被替换为“select * from temporaryTable”。 SQL优化器会决定对此列表进行排序(在某些情况下),让我们让它做到这一点,而不是第二次猜测它并明确排序。

另一个要考虑的问题是,可能会将ItemTagMap表上的连接带入“驱动查询”中,而不是像上面所示。这可能是最好的,无论是为了表现,还是因为它会产生#2目的的正确列表(显示一页的项目)。

即使在相对适中的硬件上,上述查询/流程也可能相当顺利;暂定为1/2 Million +项目,持续的用户搜索量可能高达每秒10个。其中一个关键因素是初始搜索标准的选择性。

优化思路

  • [根据典型的搜索案件和数据统计]可能是有意义将通过使(确实复制)一些项目字段到ItemTagMap表的非规范化。特别是短的领域可能是'受欢迎的'那里。随着数据量在百万以上的项目中增长,我们可以利用一些标签(例如:在SO中,PHP通常与MySql一起出现,通常没有任何理由...)和各种技巧的强关联。例如,引入“多标签”TagIds可能会使输入逻辑稍微复杂一些,但也可能会显着缩小映射的大小。


- '不说了! -
应根据实际要求和有效的数据统计资料选择适当的体系结构和优化...

+0

这是一个了不起的帖子,我想你 – y2k 2010-06-04 17:04:11

+0

@Joshua:谢谢你说的客气话。 – mjv 2010-06-07 07:05:44

+0

这是一个关于数据库模式的好文章,其中有一个,两个或三个表,用于不同的架构/性能需求:http://www.pui.ch/phred/archives/2005/04/tags-database-schemas.html – ATSiem 2012-03-14 20:21:10

0

假设:

  • 项目(ID);
  • 带有索引名称的标签(id,name);
  • ItemTag(item_id,tag_id)。

则:

SELECT t.name 
FROM Tag t 
WHERE EXISTS (SELECT 1 FROM ItemTag WHERE item_id = 1234) 
ORDER BY t.name 

没有密集有关。这是类似的,但我的猜测是,这将是更慢:

SELECT t.name 
FROM Tag t 
WHERE t.id IN (SELECT tag_id FROM ItemTag WHERE item_id = 1234) 
ORDER BY t.name 

这是可以做到的加入,以及:

SELECT DISTINCT t.name 
FROM Tag t 
JOIN ItemTag i WHERE i.tag_id = t.id 
WHERE i.item_id = 1234 
ORDER BY t.name 

我第一个想到的会更快,但因为始终是这种情况使用SQL,值得测试(在足够大小的数据集上)。

上面已经完成列出单个项目的标签。您需要一组用于搜索结果的标签。从上面这不难,但这取决于你如何获得搜索结果。

+1

我不确定这是否会回答OP。基础搜索(来自站点用户)将产生许多item_id值。我怀疑你是否建议应该单独搜索这些ID中的每一个...... – mjv 2009-10-07 01:53:18

+0

@mvj这是一个简单的修改,将它带到该级别。要将标签与多个项目进行比较,请执行'... WHERE item_id IN(...)...'。此外,为了缩小结果的标签,只需添加到子句'... WHERE item_id IN(...)和tag_id IN(...)...' – 2009-10-07 02:44:25

+0

@cletus好的item_id IN(... )部分。然而,基于Tad_Id的缩小将需要多次加入ItemTag表。对 ?    (无关)你如何评论背景颜色?很酷。 – mjv 2009-10-07 03:11:08

0

你会想尽量减少数据库调用的数量,把繁重的工作放到PHP中。

首先,从数据库中选择所有项目:

select * from items where (conditions); 

然后,创建所有的ID从结果集的数组。

$ids = array(); 
foreach ($items as $item) { 
    $ids[] = $item['id']; 
} 
$ids = implode(',' $ids); 

然后为您以前检索的项目ID选择所有ItemTagMaps和相关联的标签数据。

select map.item_id, t.id, t.name from tags t, item_tag_maps map where t.id = map.tag_id and map.item_id in ($ids); 

现在,当您通过$ items数组循环,你可以从你执行的,只要它有一个匹配ITEM_ID值二号SQL查询找到所有匹配的标签。

+0

做下面的工作效率会更高吗? select * from项目where(conditions); 从标记TM内选择t.name联接item_tag_maps地图上t.id = map.tag_id WHERE内部联接上map.item_id = ITEM_ID项目{相同的条件放在这里......}? – 2009-10-07 02:08:41

+0

此外,即使我要仅显示一页数据,您的方法也会从数据库中检索项目的整个表格。使用我的方法,我可以添加LIMIT()到第一个选择带来最小数据 – 2009-10-07 02:18:46

+0

没有迈克尔,你错了。请注意我传递给每个SELECT语句的条件。第二个SELECT只检索在第一个SELECT语句中检索到的匹配item_id的标签,并且第一个SELECT语句应该匹配第一个页面的条件。 – 2009-10-09 15:31:43

相关问题