保持SQL Server表在数据库中排序

时间:2011-01-04 15:22:39

标签: c# sql-server

在我的应用程序中,我使用一个简单的表,其中包含访问文件的次数以及上次访问该文件的日期。

我正在尝试对保存的条目进行排序,以便具有最高访问次数的文件始终位于数据库的顶部。另外,我想只对过去7天内访问过的文件进行排序。

我应该使用什么方法(考虑到执行速度)?我是否应该编写一个负责排序的存储过程,并在每次添加或修改条目时调用它?我应该在我的应用程序中查询7天以内的条目,对它们进行排序,并将它们添加到数据库的顶部吗?任何其他方法都是最受欢迎的。

谢谢,Catalin

4 个答案:

答案 0 :(得分:3)

如果在定义排序的列上添加clustered index,SQL Server将使用它来物理组织表中的行。

但是,您应始终在查询中使用ORDER BY子句,因为数据库不需要以任何特定顺序返回行。但是,使用聚簇索引的好处是,可以在检索行时降低排序行的总体成本,并且可以改进索引列上的执行范围查询。

答案 1 :(得分:2)

在您的问题中,隐含的假设是关系数据库表以某种方式排序。它不是。它代表。根据定义,集合是无序的(例如,集合[a,b,c]与[b,c,a]的集合相同)。

因此,SQL明确不保证对结果集的任何特定顺序,除非通过ORDER BY子句指定了一个。理论上,连续两次执行完全相同的查询而不使用ORDER BY可以返回具有不同排序的相同结果集(例如,表的某些页面可能已经在缓存中并在执行引擎查看其他页面之前进行检查。)

实际上,在聚类序列中返回的结果中将聚类索引放在表中(在SQL Server中会产生)(假设查询使用聚簇索引或不使用索引),因为添加聚簇索引的净效果是使表的数据页成为作为聚类索引的b树的叶节点。如果没有聚簇索引,表的数据页就在一个堆中,每个(非聚集的)索引都是一个b树,其中叶节点是指向堆中数据页的指针。

回到你的问题......

考虑一下表:

create table dbo.PublicFile
(
  id                int          not null ,
  name              varchar(500) not null ,
  access_cnt        int          not null ,
  dt_last_access    datetime     not null ,

  primary key nonclustered (id)   ,
  unique      nonclustered (name) ,

)

根据您的描述,两列access_cnt和dt_last_access都是高度动态的。每次访问文件都会导致更新这两列。如果在这些上放置聚类索引,则会遇到性能问题,因为在索引中移动行时会遇到大量页面拆分。 (你也会遇到与非聚集索引相同的问题,但页面拆分只会影响索引页面,而不会影响数据页面,这是一个小得多的列。)

首先,编写查询以获得所需的结果,而不考虑索引(这是一种优化)。此查询将为您提供过去7天内访问过的公共文件列表,按访问次数的降序排列:

select *
from dbo.PublicFile f
where f.dt_last_access >= dateadd(day,-7,current_timestamp)
order by f.access_cnt desc , f.name

根据数据的大小,这可能是服务器的原样。如果你有4或5百万行,它可能不会。您的DBA可能希望在上次访问的数据和访问计数上添加索引。我可能只使用一个索引:

create nonclustered index PublicFile_IX01
on dbo.PublicFile ( dt_last_access ,
                    access_cnt desc
                  )

但是涉及到一定数量的实验。根据查询的语义和数据的形状,查询优化器可能会也可能不喜欢它。

答案 2 :(得分:1)

您可以创建聚簇索引,以便按照您想要的顺序保留这些索引。

http://msdn.microsoft.com/en-us/library/aa174523(v=sql.80).aspx

答案 3 :(得分:0)

数据库索引重要的列(以及您指定的任何其他列),以便您可以忽略数据库中行的顺序,并确保索引正确的列。从那里,查询中的一个简单的OrderBy将负责以正确的顺序返回记录。