我有一个包含大量重复字符串数据的大表。为了节省空间,我已将字符串数据移动到单独的表中。我的表现在看起来像这样:
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
表的非聚簇索引中。
答案 0 :(得分:4)
您可能应该向标准化迈出一步,并创建一个连接表。不是在MyStringNId
中包含MyRecords
列,而是拥有第三个表:
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上有多个匹配项,那可能会有所帮助。
答案 1 :(得分:2)
我能以某种方式将其转变为单一联接吗?
如果在MyRecords
的多行中发生相同的组合字符串是很常见的,那么将这些组合存储在单独的表中是有意义的。然后你可以做一次加入。
只要您只存储单个字符串,就不可能在单个连接中执行此操作,因为它必须单独搜索每个字符串。
通过创建包含所有连接的表的视图,可以使查询更易于读取和写入。这不会提高性能,但会使您的查询看起来更好。
我如何才能提高此sp的性能?
根据数据的形式,您可以做些事情。
如果一个字段中的字符串(大部分)包含的信息与另一个字段不同,那么您可以尝试将它们放入不同的表中。如果一个字段的最大长度比另一个字段的最大长度小得多,或者如果一个字段的不同值的数量远小于另一个字段的数量,则有可能提高性能。
答案 2 :(得分:1)
第一步是运行性能分析以查看问题所在。
尽管如此,你可以通过在连接表上使用(nolock)来获得一些性能提升。