为何这个SQL语句在不同机器上,相同数据库下执行的效率相差很大!

bobzhu 2009-08-09 02:43:02
有如下SQL语句:
SELECT * FROM (SELECT ROW_NUMBER() OVER(ORDER BY pagerrank0 DESC, case   when   datediff(day,releaseTime,getdate())=0   then   1   else   0   end   desc,case  when  ISNUMERIC(price)=1 then '3' when price<>'' then '2' else '1' end desc ,releaseTime desc,productid desc) AS rownum,  *  FROM View_product  WHERE isPassAudit='true' and pagerRank0>0 ) AS D
WHERE isPassAudit='true' and pagerRank0>0 AND rownum BETWEEN 17 AND 32 ORDER BY pagerrank0 DESC, case when datediff(day,releaseTime,getdate())=0 then 1 else 0 end desc,case when ISNUMERIC(price)=1 then '3' when price<>'' then '2' else '1' end desc ,releaseTime desc,productid desc

该SQL语句主要的工作是对视图“View_Product”进行分页获取数据。我在视图上代码如下:
CREATE VIEW [dbo].[View_Product]
WITH SCHEMABINDING
AS
SELECT dbo.tb_Product.productId, dbo.tb_Product.companyId, dbo.tb_Product.productGroupId, dbo.tb_Product.productName, dbo.tb_Product.productPicture,
dbo.tb_Product.brand, dbo.tb_Product.keyWords, dbo.tb_Product.mainSpecification, dbo.tb_Product.price, dbo.tb_Product.priceUnitName,
dbo.tb_Product.measureUnitName, dbo.tb_Product.priceType, dbo.tb_Product.priceTypeCityName, dbo.tb_Product.priceValidDays,
dbo.tb_Product.supplyAbility, dbo.tb_Product.supplyAbilityMeasureUnit, dbo.tb_Product.netWeight, dbo.tb_Product.netWeightUnitName,
dbo.tb_Product.netWeightMeasureName, dbo.tb_Product.deliveryDays, dbo.tb_Product.packing, dbo.tb_Product.minOrder,
dbo.tb_Product.minOrderUnitName, dbo.tb_Product.payment, dbo.tb_Product.detailSpecification, dbo.tb_Product.productPriority, dbo.tb_Product.isAdv,
dbo.tb_Product.clickedCount, dbo.tb_Product.releaseTime, dbo.tb_Product.isPassAudit, dbo.tb_Product.pagerRank0,
dbo.tb_Seller.companyChineseName, dbo.tb_Seller.companyName, dbo.tb_Product.Model, dbo.tb_Product.displayRank
FROM dbo.tb_Product INNER JOIN
dbo.tb_SellerCompany ON dbo.tb_Product.companyId = dbo.tb_SellerCompany.companyId INNER JOIN
dbo.tb_Seller ON dbo.tb_SellerCompany.sellerId = dbo.tb_Seller.sellerId

GO
EXEC sys.sp_addextendedproperty @name=N'MS_DiagramPane1', @value=N'[0E232FF0-B466-11cf-A24F-00AA00A3EFFF, 1.00]
Begin DesignProperties =
Begin PaneConfigurations =
Begin PaneConfiguration = 0
NumPanes = 4
Configuration = "(H (1[47] 4[32] 2[15] 3) )"
End
Begin PaneConfiguration = 1
NumPanes = 3
Configuration = "(H (1 [50] 4 [25] 3))"
End
Begin PaneConfiguration = 2
NumPanes = 3
Configuration = "(H (1 [50] 2 [25] 3))"
End
Begin PaneConfiguration = 3
NumPanes = 3
Configuration = "(H (4 [30] 2 [40] 3))"
End
Begin PaneConfiguration = 4
NumPanes = 2
Configuration = "(H (1 [56] 3))"
End
Begin PaneConfiguration = 5
NumPanes = 2
Configuration = "(H (2 [66] 3))"
End
Begin PaneConfiguration = 6
NumPanes = 2
Configuration = "(H (4 [50] 3))"
End
Begin PaneConfiguration = 7
NumPanes = 1
Configuration = "(V (3))"
End
Begin PaneConfiguration = 8
NumPanes = 3
Configuration = "(H (1[56] 4[18] 2) )"
End
Begin PaneConfiguration = 9
NumPanes = 2
Configuration = "(H (1 [75] 4))"
End
Begin PaneConfiguration = 10
NumPanes = 2
Configuration = "(H (1[66] 2) )"
End
Begin PaneConfiguration = 11
NumPanes = 2
Configuration = "(H (4 [60] 2))"
End
Begin PaneConfiguration = 12
NumPanes = 1
Configuration = "(H (1) )"
End
Begin PaneConfiguration = 13
NumPanes = 1
Configuration = "(V (4))"
End
Begin PaneConfiguration = 14
NumPanes = 1
Configuration = "(V (2))"
End
ActivePaneConfig = 0
End
Begin DiagramPane =
Begin Origin =
Top = 0
Left = 0
End
Begin Tables =
Begin Table = "tb_Product"
Begin Extent =
Top = 6
Left = 38
Bottom = 121
Right = 239
End
DisplayFlags = 280
TopColumn = 4
End
Begin Table = "tb_SellerCompany"
Begin Extent =
Top = 6
Left = 277
Bottom = 159
Right = 484
End
DisplayFlags = 280
TopColumn = 0
End
Begin Table = "tb_Seller"
Begin Extent =
Top = 11
Left = 587
Bottom = 126
Right = 776
End
DisplayFlags = 280
TopColumn = 8
End
End
End
Begin SQLPane =
End
Begin DataPane =
Begin ParameterDefaults = ""
End
Begin ColumnWidths = 9
Width = 284
Width = 1500
Width = 1500
Width = 1500
Width = 1500
Width = 1500
Width = 1500
Width = 1500
Width = 1500
End
End
Begin CriteriaPane =
Begin ColumnWidths = 11
Column = 3495
Alias = 900
Table = 1170
Output = 720
Append = 1400
NewValue = 1170
SortType = 1350
SortOrder = 1410
GroupBy = 1350
Filter = 1350
Or = 1350
Or = 1350
Or = 1350
End
End
End
' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'VIEW',@level1name=N'View_Product'
GO
EXEC sys.sp_addextendedproperty @name=N'MS_DiagramPaneCount', @value=1 , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'VIEW',@level1name=N'View_Product'


在视图上建立了主键索引ProductId,非聚集索引Pagerrank0,releaseTime,price。该视图中有5万条记录。现在在我的XP下的SQL2005DEVELOPER版本中执行该存储过程只要1秒,而到了一台WIN2003SERVER+SQL2005企业版的机器上执行该存储过程需要18秒,而服务器和我本机的数据库是完全一样的,也就是说在服务器上也建立了ProductId,pagerrank0,releaseTime,price的索引。后来我在服务器上把Order By字段中的releasetime和price字段删除,发现在服务器上执行的速度就为1秒了,真的很奇怪,请高手解答!
...全文
764 35 打赏 收藏 转发到动态 举报
写回复
用AI写文章
35 条回复
切换为时间正序
请发表友善的回复…
发表回复
yulixian9 2009-08-10
  • 打赏
  • 举报
回复
配置?
Q315054403 2009-08-10
  • 打赏
  • 举报
回复
给点苦力费用,专业解决
xuejie09242 2009-08-10
  • 打赏
  • 举报
回复
[Quote=引用 31 楼 claro 的回复:]
引用楼主 bobzhu 的回复:
为何这个SQL语句在不同机器上,相同数据库下执行的效率相差很大![问题点数:100分]
看题目就不解。
首先,相同数据库并不能保证其执行效率一定相同。其次,执行效率这里表现为响应时间,往往跟系统配置有很大关系,磁盘配置又是影响数据库查询效能的一个杀手。硬件配置,系统配置以及数据库tempdb的配置都会影响数据库性能,这里表现为执行效率。
对于语句的部分需要检查是否存在table scan,通常用查询计划可以看到。
[/Quote]
有道理。
claro 2009-08-10
  • 打赏
  • 举报
回复
[Quote=引用楼主 bobzhu 的回复:]
为何这个SQL语句在不同机器上,相同数据库下执行的效率相差很大![问题点数:100分][/Quote]
看题目就不解。
首先,相同数据库并不能保证其执行效率一定相同。其次,执行效率这里表现为响应时间,往往跟系统配置有很大关系,磁盘配置又是影响数据库查询效能的一个杀手。硬件配置,系统配置以及数据库tempdb的配置都会影响数据库性能,这里表现为执行效率。
对于语句的部分需要检查是否存在table scan,通常用查询计划可以看到。
yyhust2 2009-08-10
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 sdhdy 的回复:]
这个问题,应该问微软。
[/Quote]
哈哈。
SQL77 2009-08-09
  • 打赏
  • 举报
回复
pagerRank0怎么又变成这个字段排序了????
SQL77 2009-08-09
  • 打赏
  • 举报
回复
[Quote=引用 27 楼 bobzhu 的回复:]
为了在View_Product上创建全文检索,我已经有了聚集索引productId了,因此不能再创建聚集索引了
[/Quote]
你这个只是在一个字段上建立了索引,那个字段上没建立,所以查询的时候排序占了好多
bobzhu 2009-08-09
  • 打赏
  • 举报
回复
我减少查询所获取的字段数以后,查询的速度也大大加快啊,代码如下:
SELECT *
FROM (SELECT ROW_NUMBER() OVER(ORDER BY pagerrank0 desc,releasetime desc) AS rownum,
productid,ispassaudit,pagerrank0,releaseTime
FROM View_product WHERE isPassAudit='true' and pagerRank0>0 ) AS D
WHERE isPassAudit='true' and pagerRank0>0 AND rownum BETWEEN 47985 AND 48000 ORDER BY pagerrank0 desc,releasetime desc

这又是为何呢?
bobzhu 2009-08-09
  • 打赏
  • 举报
回复
为了在View_Product上创建全文检索,我已经有了聚集索引productId了,因此不能再创建聚集索引了
SQL77 2009-08-09
  • 打赏
  • 举报
回复
CREATE CLUSTERED INDEX INDEX_ASC ON View_product(releaseTime  DESC,productid DESC)楼主改成这样试试,我这样测试的时候,有快很多,不过没按一列时查询快,索引100%
SQL77 2009-08-09
  • 打赏
  • 举报
回复
在计算列和视图上创建索引时的考虑
在 SQL Server 2000 中,还可以在计算列和视图上创建索引。在视图上创建唯一聚集索引可以提高查询性能,因为视图存储在数据库中的方式与具有聚集索引的表的存储方式相同。

UNIQUE 或 PRIMARY KEY 只要满足所有索引条件,就可以包含计算列。具体说来就是,计算列必须具有确定性、必须精确,且不能包含 text、ntext 或 image 列。有关确定性的更多信息,请参见确定性函数和非确定性函数。

在计算列或视图上创建索引可能导致前面产生的 INSERT 或 UPDATE 操作失败。当计算列导致算术错误时可能产生这样的失败。例如,虽然下表中的计算列 c 将导致算术错误,但是 INSERT 语句仍有效:

CREATE TABLE t1 (a int, b int, c AS a/b)
GO
INSERT INTO t1 VALUES ('1', '0')
GO

相反,如果创建表之后在计算列 c 上创建索引,则上述 INSERT 语句将失败。

CREATE TABLE t1 (a int, b int, c AS a/b)
GO
CREATE UNIQUE CLUSTERED INDEX Idx1 ON t1.c
GO
INSERT INTO t1 VALUES ('1', '0')
GO

在通过数字或 float 表达式定义的视图上使用索引所得到的查询结果,可能不同于不在视图上使用索引的类似查询所得到的结果。这种差异可能是由对基础表进行 INSERT、DELETE 或 UPDATE 操作时的舍入错误引起的。

若要防止 SQL Server 使用索引视图,请在查询中包含 OPTION (EXPAND VIEWS) 提示。此外,任何所列选项设置不正确均会阻止优化程序使用视图上的索引。有关 OPTION (EXPAND VIEWS) 提示的更多信息,请参见 SELECT。

对索引视图的限制
定义索引视图的 SELECT 语句不得包含 TOP、DISTINCT、COMPUTE、HAVING 和 UNION 关键字。也不能包含子查询。

SELECT 列表中不得包含星号 (*)、'table.*' 通配符列表、DISTINCT、COUNT(*)、COUNT(<expression>)、基表中的计算列和标量聚合。

非聚合 SELECT 列表中不能包含表达式。聚合 SELECT 列表(包含 GROUP BY 的查询)中可能包含 SUM 和 COUNT_BIG(<expression>);它一定包含 COUNT_BIG(*)。不允许有其它聚合函数(MIN、MAX、STDEV,...)。

使用 AVG 的复杂聚合无法参与索引视图的 SELECT 列表。不过,如果查询使用这样的聚合,则优化程序将能使用该索引视图,用 SUM 和 COUNT_BIG 的简单聚合组合代替 AVG。

若某列是从取值为 float 数据类型或使用 float 表达式进行取值的表达式得到的,则不能作为索引视图或表中计算列的索引键。这样的列被视为是不精确的。使用 COLUMNPROPERTY 函数决定特定计算列或视图中的列是否精确。

索引视图受限于以下的附加限制:

索引的创建者必须拥有表。所有表、视图和索引必须在同一数据库中创建。


定义索引视图的 SELECT 语句不得包含视图、行集函数、行内函数或派生表。同一物理表在该语句中只能出现一次。


在任何联接表中,均不允许进行 OUTER JOIN 操作。


搜索条件中不允许使用子查询或者 CONTAINS 或 FREETEXT 谓词。


如果视图定义包含 GROUP BY 子句,则视图的 SELECT 列表中必须包含所有分组依据列及 COUNT_BIG(*) 表达式。此外,CREATE UNIQUE CLUSTERED INDEX 子句中必须只包含这些列。
可以创建索引的视图的定义主体必须具有确定性且必须精确,这类似于计算列上的索引要求。请参见在计算列上创建索引。

权限
楼主参考一下
bobzhu 2009-08-09
  • 打赏
  • 举报
回复
是通过在数据表的索引项下点击鼠标右键建立的
SQL77 2009-08-09
  • 打赏
  • 举报
回复
[Quote=引用 22 楼 sql77 的回复:]
引用 21 楼 bobzhu 的回复:
引用 20 楼 sql77 的回复:
引用 19 楼 bobzhu 的回复:
我做了一个测试,当按照一个排序字段进行排序时,在执行计划中出现了索引查找的图标,如:如下代码:SQL codeSELECT*FROM (SELECT ROW_NUMBER()OVER(ORDERBY pagerrank0desc)AS rownum,*FROM View_productWHERE isPassAudit='true'and pagerRank0>0 )AS DWHERE isPassAudit='true'and pagerRank0>0AND rownumBETWEEN47985AND48000ORDERBY pagerrank0desc
当我把 pagerrank0改为releaseTime时也出现了索引查找的图标。因此查找的速度非常快才156毫秒,但若把两个条件组合起来时,如下代码:SQL codeSELECT*FROM (SELECT ROW_NUMBER()OVER(ORDERBY pagerrank0desc,releaseTimedesc)AS rownum,*FROM View_productWHERE isPassAudit='true'and pagerRank0>0 )AS DWHERE isPassAudit='true'and pagerRank0>0AND rownumBETWEEN47985AND48000ORDERBY pagerrank0desc,releaseTimedesc
则在执行计划中不会出现索引查找的图标了,不知道这是为何?还请高手指教?难道在order by时只能指定一个排序字段?指定多个排序字段后索引就无效了?

两个字段都创建索引的话应该可以的呀,我测试了下

奇怪了,我的机器上就是不行啊。要不再通过远程协助一下?

哦,原来也不行!!!刚刚又测试了下,也不行
[/Quote]
楼主你创建的索引语句是什么来看看????
SQL77 2009-08-09
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 bobzhu 的回复:]
引用 20 楼 sql77 的回复:
引用 19 楼 bobzhu 的回复:
我做了一个测试,当按照一个排序字段进行排序时,在执行计划中出现了索引查找的图标,如:如下代码:SQL codeSELECT*FROM (SELECT ROW_NUMBER()OVER(ORDERBY pagerrank0desc)AS rownum,*FROM View_productWHERE isPassAudit='true'and pagerRank0>0 )AS DWHERE isPassAudit='true'and pagerRank0>0AND rownumBETWEEN47985AND48000ORDERBY pagerrank0desc
当我把 pagerrank0改为releaseTime时也出现了索引查找的图标。因此查找的速度非常快才156毫秒,但若把两个条件组合起来时,如下代码:SQL codeSELECT*FROM (SELECT ROW_NUMBER()OVER(ORDERBY pagerrank0desc,releaseTimedesc)AS rownum,*FROM View_productWHERE isPassAudit='true'and pagerRank0>0 )AS DWHERE isPassAudit='true'and pagerRank0>0AND rownumBETWEEN47985AND48000ORDERBY pagerrank0desc,releaseTimedesc
则在执行计划中不会出现索引查找的图标了,不知道这是为何?还请高手指教?难道在order by时只能指定一个排序字段?指定多个排序字段后索引就无效了?

两个字段都创建索引的话应该可以的呀,我测试了下

奇怪了,我的机器上就是不行啊。要不再通过远程协助一下?
[/Quote]
哦,原来也不行!!!刚刚又测试了下,也不行
bobzhu 2009-08-09
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 sql77 的回复:]
引用 19 楼 bobzhu 的回复:
我做了一个测试,当按照一个排序字段进行排序时,在执行计划中出现了索引查找的图标,如:如下代码:SQL codeSELECT*FROM (SELECT ROW_NUMBER()OVER(ORDERBY pagerrank0desc)AS rownum,*FROM View_productWHERE isPassAudit='true'and pagerRank0>0 )AS DWHERE isPassAudit='true'and pagerRank0>0AND rownumBETWEEN47985AND48000ORDERBY pagerrank0desc
当我把 pagerrank0改为releaseTime时也出现了索引查找的图标。因此查找的速度非常快才156毫秒,但若把两个条件组合起来时,如下代码:SQL codeSELECT*FROM (SELECT ROW_NUMBER()OVER(ORDERBY pagerrank0desc,releaseTimedesc)AS rownum,*FROM View_productWHERE isPassAudit='true'and pagerRank0>0 )AS DWHERE isPassAudit='true'and pagerRank0>0AND rownumBETWEEN47985AND48000ORDERBY pagerrank0desc,releaseTimedesc
则在执行计划中不会出现索引查找的图标了,不知道这是为何?还请高手指教?难道在order by时只能指定一个排序字段?指定多个排序字段后索引就无效了?

两个字段都创建索引的话应该可以的呀,我测试了下
[/Quote]
奇怪了,我的机器上就是不行啊。要不再通过远程协助一下?
SQL77 2009-08-09
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 bobzhu 的回复:]
我做了一个测试,当按照一个排序字段进行排序时,在执行计划中出现了索引查找的图标,如:如下代码:SQL codeSELECT*FROM (SELECT ROW_NUMBER()OVER(ORDERBY pagerrank0desc)AS rownum,*FROM View_productWHERE isPassAudit='true'and pagerRank0>0 )AS DWHERE isPassAudit='true'and pagerRank0>0AND rownumBETWEEN47985AND48000ORDERBY pagerrank0desc
当我把 pagerrank0改为releaseTime时也出现了索引查找的图标。因此查找的速度非常快才156毫秒,但若把两个条件组合起来时,如下代码:SQL codeSELECT*FROM (SELECT ROW_NUMBER()OVER(ORDERBY pagerrank0desc,releaseTimedesc)AS rownum,*FROM View_productWHERE isPassAudit='true'and pagerRank0>0 )AS DWHERE isPassAudit='true'and pagerRank0>0AND rownumBETWEEN47985AND48000ORDERBY pagerrank0desc,releaseTimedesc
则在执行计划中不会出现索引查找的图标了,不知道这是为何?还请高手指教?难道在order by时只能指定一个排序字段?指定多个排序字段后索引就无效了?
[/Quote]
两个字段都创建索引的话应该可以的呀,我测试了下
bobzhu 2009-08-09
  • 打赏
  • 举报
回复
我做了一个测试,当按照一个排序字段进行排序时,在执行计划中出现了索引查找的图标,如:如下代码:
SELECT *
FROM (SELECT ROW_NUMBER() OVER(ORDER BY pagerrank0 desc) AS rownum,
*
FROM View_product WHERE isPassAudit='true' and pagerRank0>0 ) AS D
WHERE isPassAudit='true' and pagerRank0>0 AND rownum BETWEEN 47985 AND 48000 ORDER BY pagerrank0 desc

当我把 pagerrank0改为releaseTime时也出现了索引查找的图标。因此查找的速度非常快才156毫秒,但若把两个条件组合起来时,如下代码:
SELECT *
FROM (SELECT ROW_NUMBER() OVER(ORDER BY pagerrank0 desc,releaseTime desc) AS rownum,
*
FROM View_product WHERE isPassAudit='true' and pagerRank0>0 ) AS D
WHERE isPassAudit='true' and pagerRank0>0 AND rownum BETWEEN 47985 AND 48000 ORDER BY pagerrank0 desc,releaseTime desc

则在执行计划中不会出现索引查找的图标了,不知道这是为何?还请高手指教?难道在order by时只能指定一个排序字段?指定多个排序字段后索引就无效了?
bobzhu 2009-08-09
  • 打赏
  • 举报
回复
在我本机上也是这样!要不我们通过QQ请你远程协助来看一下?我的QQ:1639738,谢谢
SQL77 2009-08-09
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 bobzhu 的回复:]
执行计划中只出现两个“排序”的图标,一个开销为0%另一个开销为98%,在这两个排序图标中的排序依据中出现了这几个字段的名称,但在执行几乎中没有直接出现具体releasetime,price等那些建立索引字段名为名称的图标
[/Quote]
在你自己那里执行呢???应该有个索引没利用起来
bobzhu 2009-08-09
  • 打赏
  • 举报
回复
执行计划中只出现两个“排序”的图标,一个开销为0%另一个开销为98%,在这两个排序图标中的排序依据中出现了这几个字段的名称,但在执行几乎中没有直接出现具体releasetime,price等那些建立索引字段名为名称的图标
加载更多回复(15)

22,206

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 疑难问题
社区管理员
  • 疑难问题社区
  • 尘觉
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧