【问题标题】:Slow SQL Server 2008 R2 performance?SQL Server 2008 R2 性能缓慢?
【发布时间】:2019-10-20 16:10:29
【问题描述】:

我在我的开发机器(不是服务器机器)上使用 SQL Server 2008 R2。

我有一个包含 1250 万条记录的表。它有 126 列,其中一半是 int。大多数行中的大多数列都是 NULL。我还使用 EAV 设计进行了测试,它返回相同记录的速度似乎快了 3-4 倍(但这意味着旋转数据以使其在表格中呈现)。

我有一个对数据进行分页的网站。当用户试图转到记录的最后一页(最后 25 条记录)时,结果查询是这样的:

select * from (
  select 
    A.Id, part_id as PartObjectId, 
    Year_formatted 'year', Make_formatted 'Make',
    Model_formatted 'Model',
    row_number() over ( order by A.id ) as RowNum
  FROM vehicles A
) as innerQuery where innerQuery.RowNum between 775176 and 775200

...但这需要将近 3 分钟才能运行。这似乎太过分了?有没有更好的方法来构造这个查询?在浏览器前端,我使用 jqGrid 来显示数据。用户可以导航到下一页、上一页、第一页或最后一页。他们还可以过滤和排序数据(例如:显示 Make 为“Bugatti”的所有记录)。

vehicles.Id 是 int 并且是主键(集群 ASC)。 part_id 是 int,Make 和 Model 是 varchar(100),通常只包含 20 - 30 个字符。

表格车辆在单个交易中每天更新约 100 次,每天 8 小时有 20 到 30 名用户使用该网页查看、搜索和编辑/添加车辆。它被大量阅读和更新。

将车辆表分割成多个表,每个表只包含 300 万条记录是否明智?这会对性能产生很大影响吗?

我看到很多视频和网站都在谈论人们拥有超过 1 亿行的表格,这些表格经常被读取和更新而没有问题。

请注意,我观察到的性能问题发生在我自己的开发计算机上。该数据库具有专用的 16GB RAM。为此,我没有使用 SSD 甚至 SCSI。所以我知道硬件会有所帮助,但检索最后 25 条记录的 3 分钟似乎有点过分,不是吗?

虽然我在 SQL Server 2008 R2 上运行这些测试,但如果这样做有很多好处,我也可以使用 2012。

【问题讨论】:

  • 您为什么使用不受支持的数据库进行此类处理? SQL Server 2016 甚至在 Express 版本中也支持列存储索引和内存表。你现在尝试做的,已经可用了。只需使用内存表和/或列存储,您就可以获得 1000 倍的改进。
  • 一般来说,我强烈建议您不要因为开发环境中没有在生产环境中出现的问题而更改工作数据库结构和工作查询。获取两种环境中查询的解释计划,并找出不同之处。这可能是您的开发计算机上的配置问题、硬件问题、过时的统计信息 - 即有很多潜在原因。在你的开发机器上表现良好的东西实际上可能在生产中表现不佳!
  • @PanagiotisKanavos 我工作的公司的客户也决定了我们绑定的数据库。

标签: sql-server-2008-r2


【解决方案1】:

是的,有更好的方法,即使在旧版本的 MsSQL 上也是如此,但它涉及到。首先,这个过程应该在存储过程中完成。存储过程应作为其输入参数中的 2 个,请求的页面 (@page) 和页面大小(每页的记录数 - @pgSiz)。

在存储过程中,

创建一个临时表变量,并将所有记录的整数主键的排序列表放入其中,其中 rowNumber 列本身就是临时表的索引整数主键

 Declare @PKs table 
    (rowNo integer primary key Identity not null, 
     vehicleId integer not null)
 Insert @PKS (vehicleId)
 Select vehicleId from Vehicles
 Order By --[Here put sort criteria as you want pages sorted]
          --[Try to only include columns that are in an index]

然后,根据用户请求的页面(和页面大小)(@page,@pgSiz),存储的过程通过加入这个临时表变量来选择该页面的实际数据:

 Select [The data columns you want]
 From @PKS p join Vehicles v
    on v.VehicleId = p.VehicleId 
 Where rowNo between @page*@pgSiz+1 and (@page+1)*@pgSiz 
 order by rowNo -- if you want to sort page of records on server

假设 @page 从 0 开始。此外,存储过程将需要一些输入参数验证,以确保 @page@pgSize 值是合理的(不要将代码放在记录的末尾。)

【讨论】:

  • 谢谢,我试试看。
  • 太棒了!我的查询时间从大约 3 分钟缩短到 6 秒!谢谢
  • 我的旧方法是否很慢,因为在内部对记录进行排序时,它会在排序时复制每一行中的数据?
  • 不,因为它正在从磁盘读取整个表。我描述的方式,它只需要读取主键列,以及您按顺序排列的任何列,它们很可能在一个更窄的索引中(磁盘上的页面更少)。如果所有内容都在索引中,那么它可能不必读取实际表本身来生成表变量,只需读取索引即可。然后当它实际获取一页数据时,它只是从磁盘中读取该页上的记录的数据。
  • 第二个查询需要按p.rowNo排序。如果我不这样做,第二个查询(将 PK 连接到 Vehicles)不会按照它们在 PK 中存储的顺序返回车辆。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-29
相关资源
最近更新 更多