Sql 处理每个对象的多个选择的最佳方法

Sql 处理每个对象的多个选择的最佳方法,sql,sql-server,Sql,Sql Server,我想知道从数据库中的多个表中检索数据的最佳方法。遗憾的是,我找不到任何东西来帮助我理解正确的方法是什么 假设我有一个名为ContentPages的内容页表。此表由以下字段组成: PageID PageTitle PageContent PageID TagID 现在,除了ContentPages表之外,我还有一个ContentPagesTags表,它负责存储最能描述页面内容的标签(就像这个网站中的stackoverflow,在这里你可以对你的问题应用特定的标签)。ContentPagesTa

我想知道从数据库中的多个表中检索数据的最佳方法。遗憾的是,我找不到任何东西来帮助我理解正确的方法是什么

假设我有一个名为ContentPages的内容页表。此表由以下字段组成:

PageID
PageTitle
PageContent
PageID
TagID
现在,除了ContentPages表之外,我还有一个ContentPagesTags表,它负责存储最能描述页面内容的标签(就像这个网站中的stackoverflow,在这里你可以对你的问题应用特定的标签)。ContentPagesTags表由以下字段组成:

PageID
PageTitle
PageContent
PageID
TagID
ContentPagesTags表负责页面和附加标签之间的关系。TagID字段取自最后一个表PageTags,该表存储了可应用于内容页的所有可能标记。最后一个表结构如下所示:

TagID
TagTitle
差不多就是这样。现在,每当我想要检索一个从其数据表中提取所需信息的ContentPage对象时,我还想加载一个包含所有相关标记的数组。默认情况下,到目前为止,我一直在运行两个独立的查询以实现我的目标:

SELECT * FROM ContentPages
然后在返回ContentPage对象之前,在每个页面上运行下一个查询:

SELECT * FROM ContentPagesTags WHERE PageID = @PageID
使用PageID作为当前页面的ID,我正在构建一个对象

总而言之,我对每个内容页对象运行(至少)两个查询,以便检索所有需要的信息。在这个特定的示例中,我只展示了如何从一个表中提取信息,但随着时间的推移,我发现自己在每个对象上运行多个查询,以获取所需的信息(例如,除了页面标签之外,我还想选择页面注释、页面草稿和可能需要考虑的附加信息)。这最终使我能够查询多个命令,这使得我的Web应用程序运行得比预期慢得多。
我很确定有更好、更快、更高效的方法来处理这些任务。我很高兴能在这个问题上有所了解,以便提高我对不同SQL选择的知识,以及如何处理用户请求的大量数据,而不必对每个对象进行多次选择。

我建议标记位于分隔列表中。您可以在SQL Server中通过以下查询执行此操作:

select cp.*,
       stuff((select ', ' + TagTitle
              from ContentPagesTags cpt join
                   PageTags pt
                   on cpt.TagId = pt.TagId
              where cpt.PageId = cp.PageId
              for xml path ('')
             ), 1, 2, '') as Tags
from ContentPages cp;

应该说,字符串连接的语法不够直观。其他数据库对此有很好的功能(例如
listag()
group_concat()
)。但是,性能通常是相当合理的,特别是如果您有适当的索引(包括
ContentPagesTags(PageId,TagId))的话
)。

在等待澄清我在对原始问题的评论中提出的问题时,我至少可以这样说:

从纯“查询性能”的角度来看,这些信息在相互不相关方面是完全不同的(即,[标记]和[注释]表)在
PageID
关系之外,但肯定不是在这些额外表之间的逐行基础上。因此,除了以下内容之外,没有其他方法可以提高查询级别的效率:

  • 确保将所有子表之间的
    PageID
    外键设置回
    [ContentPages]

  • 确保在每个子表的
    PageID
    字段中都有索引(根据使用模式,非聚集应该可以,填充因子为90-100)

  • 确保定期执行索引维护。至少要经常重新组织,必要时重建

  • 确保表正确建模:使用适当的数据类型(即不要使用INT来存储最坏情况下永远不会超过10或50的1-10的值,因为在应用层编写
    INT
    更容易;不要对任何PK或聚集索引使用UNIQUEIDENTIFIER;等等)。严重:数据建模不好(数据类型和结构)可能会损害某些甚至所有查询的总体性能,因此,任何数量的索引或任何其他功能或技巧都不会有帮助

  • <> >如果您有企业版,请考虑启用行或页压缩(是索引的一个特征),特别是对于诸如“代码> >注释[<代码] >的表,或者甚至是一个大型关联表,如<代码> [Cordon Page Stabs] < /C> >如果它将非常大(按行计数)as压缩允许使用较小的固定长度数据类型来存储声明为较大类型的值。意思是:如果您有
    INT
    (4字节)或
    BIGINT
    (8字节)对于
    TagID
    来说,标识值需要超过
    SMALLINT
    数据类型使用的2个字节需要很短的时间,超过
    INT
    数据类型的4个字节需要很长的时间,但是SQL Server将在2个字节的空间中存储1005的值,就像它是
    SMALLINT
    一样。从本质上讲,减少行大小将使每个8k数据页上容纳更多的行(这是SQL Server读取和存储数据的方式),从而减少物理IO并更好地利用缓存在内存中的数据页

  • 如果并发性是(或成为)一个问题,请签出

现在,从应用程序/进程的角度来看,您希望减少连接/调用的数量。您可以尝试将一些信息合并到CSV或XML字段中,以与每个
PageID
/
PageContent
行成1:1的形式结束,但这实际上效率较低
// assume the code block 2 blocks above is right here

SqlDataReader _Reader;
_Reader = _Command.ExecuteReader();
DataSet _Results = new DataSet();

if (_Reader.HasRows)
{
   _Results.Load(_Reader, LoadOption.Upsert, "Content", "Tags", "Comments");
}
else
{
    throw new Exception("PageID " + _PageID.ToString()
                + " does not exist. What were you thinking??!?");
}