【问题标题】:How to efficiently join records with separate string table如何有效地使用单独的字符串表连接记录
【发布时间】:2011-05-05 15:56:30
【问题描述】:

我有一个包含大量重复字符串数据的大表。为了节省空间,我将字符串数据移到了单独的表中。我的表格现在看起来像这样:

MyRecords
RecordId (int) | FieldA (int) | FieldB (datetime) | FieldC (...) | MyString1Id (int) | MyString2Id (int) | MyString3Id (int) | ...

MyStrings
StringId (int) | StringValue (varchar)

MyRecords 表有大约 10 个指向字符串表的外键。我有一个存储过程GetMyRecords,它检索具有实际字符串值的记录列表。对于每个字符串关系,这个 sp 现在有 10 个到字符串表的连接:

SELECT [Field1], [Field2], [Field3], ..., [Strings1].[StringValue], [Strings2].[StringValue], ...
 FROM MyRecords INNER JOIN
   MyStrings AS Strings1 ON MyRecords.MyString1Id = Strings1.StringId INNER JOIN
   MyStrings AS Strings2 ON MyRecords.MyString2Id = Strings2.StringId INNER JOIN
   MyStrings AS Strings3 ON MyRecords.MyString3Id = Strings3.StringId INNER JOIN
            (more joins)
    WHERE [Field1] = @Field1 AND [Field2] = @Field2

GetMyRecords 比我想要的慢得多,因为所有的连接。我怎样才能提高这个 sp 的性能?我能不能把它变成一个单一的连接?

strings 表在StringId 上有一个聚集主键,所有 where 字段都在MyRecords 表的非聚集索引中。

【问题讨论】:

  • 你真的应该规范你的结构……这不是真正可扩展的,维护起来很残酷。

标签: sql-server sql-server-2008 stored-procedures join


【解决方案1】:

您可能应该朝着规范化进一步迈出一步,并创建一个连接表。不要在MyRecords 中使用MyStringNId 列,而是使用第三个表:

CREATE TABLE RecordsStrings (
    RecordId [theDataType] NOT NULL REFERENCES MyRecords (RecordId),
    StringId [theDataType] NOT NULL REFERENCES MyStrings (StringId)
)

然后将所有字符串放在来自SELECT 的返回数据的同一行中并不方便(尽管也许有一种方法可以通过某种方式使用枢轴来做到这一点),因此重组调用代码可能会更好处理返回的结果:

SELECT [StringValue]
FROM   [MyStrings] s
INNER JOIN [RecordsStrings] rs ON rs.StringId = s.StringId
INNER JOIN [MyRecords] r ON rs.RecordId = r.RecordId
WHERE  r.Field1 = @Field1 AND r.Field2 = @Field2

如果您需要来自MyRecords 的其他字段,您也可以选择这些字段,尽管它们会出现在每个相关行中。但是,如果您在 Field1 和 Field2 上有多个匹配项,那可能会有所帮助。

【讨论】:

  • 好答案。在向我解释之前,我对多对多问题感到沮丧。我曾经购买过 Michael J. Hernandez 的“Database Design For Mere Mortals”的最佳 db 书籍。国际标准书号:0-201-69471-9
  • 标准化似乎不可能。我怎么知道哪个字符串与哪个列对应?我必须在连接表中添加另一列。
  • @Jappie 如果重要的是哪一列与哪个字符串一起使用,那是真的。我做了一个(显然很糟糕的)假设,即字符串的顺序无关紧要。那么,为了提高性能,最好按照您的建议在连接表中添加一列,而不是像原始问题中的查询那样经历多个连接。
【解决方案2】:

我能不能把它变成一个单一的连接?

如果相同的字符串组合经常出现在MyRecords 的多行上,那么将这些组合存储在单独的表中是有意义的。然后你可以做一个单一的连接。

只要您只存储单个字符串,就不可能在单个连接中执行此操作,因为它必须单独搜索每个字符串。

您可以通过创建包含所有联接的表视图来使查询更易于阅读和编写。这不会提高性能,但会让您的查询看起来更好。

我怎样才能提高这个 sp 的性能?

您可以做一些事情,具体取决于数据的形式。

如果一个字段中的字符串包含(大部分)与另一字段不同的信息,那么您可以尝试将它们放入不同的表中。如果一个字段的最大长度比另一个字段小得多,或者一个字段的不同值的数量比另一个字段少得多,这可能会提高性能。

【讨论】:

    【解决方案3】:

    第一步是运行性能分析以查看问题所在。

    不过,您可以通过在连接表上使用 (nolock) 来获得一点性能提升。

    【讨论】:

      猜你喜欢
      • 2010-12-18
      • 1970-01-01
      • 1970-01-01
      • 2013-03-11
      • 2013-12-06
      • 1970-01-01
      • 1970-01-01
      • 2019-02-08
      • 1970-01-01
      相关资源
      最近更新 更多