SQL主键排序顺序

时间:2010-09-03 19:45:32

标签: sql sql-server-2005 sorting

我正在使用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

由于

4 个答案:

答案 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,您可以使用聚集索引来实现这一目标。