继续提问“用于存储标记记录的DB模式” - 如何选择带有标记的项目列表?

时间:2009-09-06 19:31:39

标签: sql linq linq-to-sql optimization

美好的一天!

有很多问题如何在stackoverflow上在DB中存储标签,我最终决定使用Toxi方法(项目表,标签表和多对多中间表)http://www.pui.ch/phred/archives/2005/04/tags-database-schemas.html

我想在页面上显示20-50个标记项目的列表,每个项目都包含它的标记列表(我在ASP.NET 3.5中使用LINQ2SQL)。

我看到了一些选择:

  1. 首先查询项目列表而不是每个项目的运行查询以选择每个项目的标签 - 似乎很慢,但在应用程序级别缓存可以改善情况。

  2. 在“items”表格的文本字段中对项目标签进行非规范化处理并存储标签列表。

  3. 然而这两种选择对我来说都很糟糕,可能是我错过了什么?

    提前致谢!

3 个答案:

答案 0 :(得分:0)

我不推荐选项#2,因为它会过多地复制隔离标签或标签组的尝试。我的建议是保持数据模型不变(ITEMSTAGSITEM_TAGS_XREF),并查询包含包含标记列表的计算列的VIEW。如果您提到了您正在使用的数据库,我们可以提供将构建与项目关联的标记的逗号/ etc分隔字符串的查询。

假设相应地设置了主键和外键,性能应该不错 - 是否可能在应用层中发生延迟?

答案 1 :(得分:0)

如果我理解正确......

也许你可以创建一个连接所有三个表的查询。在一个快速查询中,您将获得所有信息......在SQL中,它可能类似于:

    select ... //itemColumns, tagColumns
    from item
    join tagItem on item.id = tagItem.itemId
    join tag on tag.id = tagItem.tagId
    where ... // your other conditions

答案 2 :(得分:0)

2KLE:谢谢,我明白了。对于每个标记,此查询的结果是一行(项目数据是重复的),因此无论如何需要在应用程序代码中处理结果集。我是对的吗?

对于LINQ 2 SQL,我使用DataLoadOptions来指定要加载的关联数据。以下是LINQ2SQL生成的代码示例,用于选择包含所有标记的所有项目。

请注意,在我的示例中,Items表称为Snippets(因此我们有Snippets,Tags和SnippetsTags表)。另外需要注意的是LINQ2SQL不支持开箱即用的多对多关系,因此有一个实体类用于中间表(SnippetsTag)。这是C#代码:

            using (SnippetsDataContext context = UtilsLinq.CreateContext())
        {
            DataLoadOptions dl = new DataLoadOptions();
            dl.LoadWith<Snippet>(s => s.SnippetsTags);
            dl.LoadWith<SnippetsTag>(st => st.Tag);
            context.LoadOptions = dl;
            var result = (from s in context.Snippets
                          select s).ToList();

            string x = result.First().SnippetsTags.First().Tag.Title;
        }

这是LINQ to SQL生成的SQL:

    SELECT [t0].[Id], [t0].[Title], [t0].[Text], [t0].[Created], [t1].[Id] AS [Id2], [t1].[TagId], [t1].[SnippetId], [t2].[Id] AS [Id3], [t2].[Title] AS [Title2], (
    SELECT COUNT(*)
    FROM [dbo].[SnippetsTags] AS [t3]
    INNER JOIN [dbo].[Tags] AS [t4] ON [t4].[Id] = [t3].[TagId]
    WHERE [t3].[SnippetId] = [t0].[Id]
    ) AS [value]
FROM [dbo].[Snippets] AS [t0]
LEFT OUTER JOIN ([dbo].[SnippetsTags] AS [t1]
    INNER JOIN [dbo].[Tags] AS [t2] ON [t2].[Id] = [t1].[TagId]) ON [t1].[SnippetId] = [t0].[Id]
ORDER BY [t0].[Id], [t1].[Id], [t2].[Id]