在我们进入提前优化模式之前,查看下面的查询模板可能很有用。如果没有其他可以用来作为衡量可能的优化效果的基线。
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可能会使输入逻辑稍微复杂一些,但也可能会显着缩小映射的大小。
- '不说了! -
应根据实际要求和有效的数据统计资料选择适当的体系结构和优化...
来源
2009-10-07 02:30:43
mjv
在增加要求的风险下,是不是也很好地显示COUNT每个标签,对应一个特定的搜索? – mjv 2009-10-07 02:04:53
是的,我会这样做 - 我甚至统计每个标签存储在单独的表中。 – 2009-10-07 02:11:25