我正在使用MS SQL server 2005
我有一个包含3列的表,我在其中存储用户消息映射,如:
msg_for msg_from msg_id
bob bob 1
bob john 1
bob steve 1
bob bob 2
bob john 2
bob bob 3
bob john 3
bob steve 3
PK在3列上,msg_id是FK到存储消息的消息表
以上是我根据3列上的PK看到的物理存储
现在我的查询必须返回顶部有最新消息的给定用户的消息(按msg_id DESC排序)
bob john 3
bob steve 3
bob john 2
bob steve 2
bob john 1
bob steve 1
此映射表有数百万行。我看到95%的成本是对结果进行排序。
是否可以让PK或其他方式存储物理数据(避免SORT)?
msg_for msg_from msg_id
bob bob 3
bob john 3
bob steve 3
bob bob 2
bob john 2
bob bob 1
bob john 1
bob steve 1
由于
答案 0 :(得分:4)
是。
设置主键(或任何索引)时,您可以定义此
ALTER TABLE dbo.[Messages] ADD CONSTRAINT [PK_Messages] PRIMARY KEY CLUSTERED
(
msg_for ASC, msg_from ASC, msg_id DESC
)
SQL Server可以向任一方向扫描,因此只有在您想要控制多列的排序顺序组合时才有意义。
编辑:您在评论中说问题查询是
select top 10 msg_id
from message_user
where msg_for = @user_name
and msg_from <> @user_name
order by msg_id DESC
这里的问题不是Ascending,Descending。
进行类比。电话簿以姓氏,姓名顺序列出,但如果您需要知道目录中的字典最后10个名字,则需要扫描整本书。无论每个部分的名字是否按升序或降序列出,这都是不可避免的。
类似地,复合索引键需要msg_for, msg_id, msg_from
才能最佳地满足此查询而不是msg_for, msg_from, msg_id
使用后一个顺序,它仍然需要扫描满足{{1}的索引的整个部分}条件,因为它无法知道以后的msg_for = @user_name
是否仍然属于后来的msg_id
此外,无论在哪个方向msg_from
按其各个子部分进行排序,顺序扫描索引的msg_id
部分仍然需要排序,因为它们根据msg_for = @user_name
在子部分中进行了分段。
答案 1 :(得分:3)
保证结果集中顺序的唯一方法是使用ORDER BY。
在SQL Server中,聚簇索引可以帮助...假设优化器将索引视为有用。
答案 2 :(得分:1)
难怪排序需要永远。 Varchar / string类型通常是排序时非常繁重的类型,无论是SQL还是任何编程语言。尽可能使用整体类型来做这些事情。
我建议您使用积分值来识别成员。拥有Members
表格(MemberId INT, MemberName VARCHAR, etc)
,然后是Messages
表格(MessageId INT, MessageBody VARCHAR, etc)
,然后有一个联接表,例如Correspondence
和(SenderMemberId INT, RecipientMemberId INT, MessageId INT)
。通过这种方式对积分值进行排序会更快。
我认为您可以轻松地重构数据以适应这种新结构。
答案 3 :(得分:0)
根据您的DBMS,您可以使用聚集索引来实现这一目标。