我正在用PHP/MySQL编写一个网站,我想实现一个类似于stackoverflow标记引擎.我在DB中有3个相关表:1.项2.标签3. ItemTagMap(将标签映射到项目,n:n映射)
现在,在搜索页面上,我想显示整个搜索结果(不仅仅是当前页面)的所有标签的不同列表,以便用户可以通过添加/删除该标签列表中的标签来"优化"他们的搜索.
问题是,这是一个相当繁重的数据库查询,可能会有大量的搜索请求导致不同的结果集,从而导致不同的标记集.
有谁知道如何有效地实现这一点?
在我们进入过早优化模式之前,查看以下查询模板可能很有用.如果没有别的可以用作可以衡量可能优化的有效性的基线.
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
Run Code Online (Sandbox Code Playgroud)
子查询是"驱动查询",即对应于最终用户初始标准的查询.(有关此查询如何多次可能适合整体优化流程的详细信息,请参见下文)注释是T1上的JOIN(可能是T2,T3,当选择了多个标签时),并且,与WHERE子句相关联标准.当用户选择特定标签时,无论是作为初始搜索的一部分还是通过细化,都需要这些.(放置这些连接以及子查询中的where子句可能更有效;更多关于以下内容)
讨论...... 出于两个不同的目的,需要"驱动查询"或其变体:
请注意,完整列表不需要排序(或者它可能受益于以不同顺序排序),因此第二个列表需要根据用户的选择进行排序(例如按日期,降序或标题,按字母顺序升序).另请注意,如果需要任何排序顺序,查询的成本将意味着处理完整列表(不熟悉SQL本身的奇怪优化,和/或一些非规范化,SQL需要"看到"该列表上的最后记录,如果他们属于顶部,排序方式).
后一个事实,有利于为两个目的具有相同的查询,相应的列表可以存储在临时表中.一般流程是快速查找前N个项目记录及其详细信息,并立即将其返回给应用程序.然后,应用程序可以获得ajax-fashion标签列表以进行优化.此列表将使用类似于上面的查询生成,其中子查询由"select*from temporaryTable"替换.SQL优化器将决定对此列表进行排序(在某些情况下)的可能性很大,让我们让它做到这一点,而不是第二次猜测并明确地对其进行排序.
要考虑的另一点是,可以将ItemTagMap表中的连接带到"驱动查询"中,而不是如上所示.最好这样做,既可以提高性能,也可以为#2目的生成正确的列表(显示项目页面).
即使在相对适中的硬件上,上述查询/流程也可能相当好地扩展; 暂时进入1/2万+项目,持续的用户搜索可能达到每秒10次.其中一个关键因素是初始搜索标准的选择性.
优化的想法
- '够说!-
应根据实际要求和有效数据统计资料选择适当的架构和优化......
| 归档时间: |
|
| 查看次数: |
4015 次 |
| 最近记录: |