【问题标题】:Optimize my Azure SQL PaaS Table and/or query to increase performance优化我的 Azure SQL PaaS 表和/或查询以提高性能
【发布时间】:2017-11-20 11:09:17
【问题描述】:

我正在设计一个具有非常专业的使用模式的表格。 该表将在流量有限的情况下连续记录 - 每秒约 25 条记录,然后我每天晚上运行一个大查询以提取大量数据。

我的表创建脚本目前如下所示:

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

IF NOT EXISTS (select * from sysobjects where name='records' and xtype='U')
CREATE TABLE [dbo].[records](
    [TripID] varchar(255) NOT NULL,
    [RecordTimeUTC] datetime2(0) NOT NULL,
    [TimeOfDaySeconds] [int] NOT NULL,
    [T0Latitude] [float] NOT NULL,
    [T0Longitude] [float] NOT NULL,
    [T1Latitude] [float] NULL,
    [T1Longitude] [float] NULL,
    [T2Latitude] [float] NULL,
    [T2Longitude] [float] NULL,
    [T3Latitude] [float] NULL,
    [T3Longitude] [float] NULL,
    [T4Latitude] [float] NULL,
    [T4Longitude] [float] NULL,
    [T5Latitude] [float] NULL,
    [T5Longitude] [float] NULL,
    [VehicleID] [int] NULL,
    [ID] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY
) ON [PRIMARY]
GO

IF NOT EXISTS (select * from sys.indexes where name='TripIDRecordTimeIndex' and object_id = OBJECT_ID('dbo.records'))
    CREATE INDEX TripIDRecordTimeIndex ON records (TripID, RecordTimeUTC desc)
GO

IF NOT EXISTS (select * from sys.indexes where name='TripIDIndex' and object_id = OBJECT_ID('dbo.records'))
    CREATE INDEX TripIDIndex ON records (TripID)
GO

IF NOT EXISTS (select * from sys.indexes where name='RecordTimeUTCIndex' and object_id = OBJECT_ID('dbo.records'))
    CREATE INDEX RecordTimeUTCIndex ON records (RecordTimeUTC desc)
GO

IF NOT EXISTS (select  * from sys.objects where name like 'UniqueConstraint2' and parent_object_id = OBJECT_ID('dbo.records'))
    ALTER TABLE [dbo].[records] ADD CONSTRAINT UniqueConstraint2 UNIQUE(VehicleID, RecordTimeUTC desc);
GO

IF NOT EXISTS (select * from sys.indexes where name='VehicleIDIndex' and object_id = OBJECT_ID('dbo.records'))
    CREATE INDEX VehicleIDIndex ON records (VehicleID)
GO

我的表中目前有大约 6000 万条记录,大小不到 50 GB。

提取数据的查询非常耗时。目前需要一个多小时。我不确定是我的表设计还是查询设计是根本原因(尽管可能两者兼而有之)。

我需要为我指定的一组 TripID 中的每个 TripID 提取最新的 X 个项目。大约有 10k 个不同的 ID,我通常想查询其中的一半。 X 在它们之间也有所不同,所以我目前最好的查询方法是生成一个看起来有点像这样的脚本:

SELECT rs.* FROM (SELECT *, ROW_NUMBER() over (Partition BY TripID ORDER BY RecordTimeUTC DESC ) AS Rank FROM records where TripID in (20141000,20441000,30011022,30011021,30011008,30012029,30012028,30012027,30011007,30011019,30011018,30012026,30012025,30012024,30011017,30011016,30012023,30012022,30011015,30011014,30012021,30012020,30011013,30011012,30013000,30013001,30013019,30013009,30011011,30011010,30011009,30013008,30013007,30012010,30012009,30013005,30013004,30013003,30012014,30012019,30013021,30013020,30011006,30011004,30012018,30012017,30012016,30013006,30011003,30011002,30012015,30012013,30013013,30013002,30011001,30011000,30011020,30012012,30012011,30011005,30011030,30012001,30012008,30012007,30011029,30011028,30012006,30012005,30011031,30011027,30012004,30012003,30011026,30011025,30011024,30012002,30012000,30012031,30011023,30012030,30015005,30016006,30016013,30016012,30014020,30014019,30014018,30016011,30016010,30014017,30014016,30016009,30016008,30014015,30014013,30014012,30016005,30016004,30016003,30014010,30014009,30016002,30016001,30014008,30014007,30016000,30016007,30014006,30014005,30014004,30014003,30014002,30014001,30014000,30014023,30014014,30015012,30015004,30015003,30013018,30013017,30015002,30015001,30013016,30013015,30013014,30015000,30015013,30015011,30013012,30013011,30015010,30015009,30013010,30014011,30015008,30015007,30014022,30014021,30015006,33651001,33661006)) rs WHERE Rank <= 690
 UNION 
SELECT rs.* FROM (SELECT *, ROW_NUMBER() over (Partition BY TripID ORDER BY RecordTimeUTC DESC ) AS Rank FROM records where TripID in (20431003,20431002,20431001,20432003,20432002,20432001,30221001,33861002,33861003)) rs WHERE Rank <= 855
 UNION 
SELECT rs.* FROM (SELECT *, ROW_NUMBER() over (Partition BY TripID ORDER BY RecordTimeUTC DESC ) AS Rank FROM records where TripID in (20171029,20171030,20002002,26122001)) rs WHERE Rank <= 45
 UNION 
...

(上面的查询在第一个列表中返回每个行程的 690 个实例,在第二个列表中返回 855 个实例,在第三个中返回 45 个,依此类推。查询比这要大得多 - 这只是一个 sn-p它。我总共提取了 10-1500 万行)

如前所述,我的表现很糟糕。是云的事吗?它是设计的东西吗?我应该使用聚集索引吗? (对 TripID 进行了尝试,但情况更糟)。我可以以某种方式改进我的查询吗?例如为每个 ID 提取相同数量的实例,然后过滤?

我注意到我有几个额外的索引可能不会在我的查询中使用。我只是尝试添加更多,因为插入性能不是问题。计划是在我的查询中使用 TripIDRecordTimeIndex。

即使将 Azure SQL 中的数据计划扩展到 S7 (800 DPU),我也无法快速运行。感谢您提供任何反馈。

编辑:我最近将 TripID 从 int 更改为 varchar(255) - 这会影响我的表现吗?

Edit2:执行计划:

Download link to full execution plan

Edit3:发现在我查询的 TripID 周围添加引号 ('') 极大地提高了性能!

Edit4:我添加了 TheGameiswar 提出的索引 - 区别在于白天和黑夜!谢谢!附上新的执行计划。

New Execution plan

【问题讨论】:

  • 这是一个非常广泛的问题。首先,您是否查看过查询的 SQL 执行计划?
  • 这是一个我知之甚少的领域。我在问题的底部为执行计划的子集添加了执行计划的副本。我意识到这是一个广泛的问题,但原因是我不知道去哪里找。感谢您的反馈。
  • 计划图片不是查询计划。您需要链接到文件:meta.stackexchange.com/questions/47689/…
  • 检查执行计划时的一般想法是查看查询中花费最多时间的步骤。在您的情况下,有两个聚集索引扫描。由于您的表有 60M 行,这会受到影响。您可以在此处阅读有关索引查找与扫描的信息:blog.sqlauthority.com/2007/03/30/…
  • 您正在扫描整个表,然后稍后进行过滤。性能只会变得更糟。您需要能够在检索数据之前对其进行过滤。但是,您是说要求需要访问一半的数据。这总是会导致扫描。这是一个设计问题,而不是云问题。

标签: sql performance azure azure-sql-database azure-sql-server


【解决方案1】:
SELECT rs.* FROM (SELECT *, 
ROW_NUMBER() over (Partition BY TripID ORDER BY RecordTimeUTC DESC ) 
AS Rank FROM records where TripID in (20141000,20441000,30011022,30011021,30011008,30012029,30012028,30012027,30011007,30011019,30011018, 30012026,30012025.....)) rs WHERE Rank <= 690

您拥有的索引对于查询的以下部分没有用...

SELECT *, 
ROW_NUMBER() over (Partition BY TripID ORDER BY RecordTimeUTC DESC ) 
AS Rank FROM records where TripID in

我会创建一个如下所示的索引

create index nci_sometst on table (tripid,recorddatetime)
include(<remaining columsn you are selecting>)

上面的查询可以帮助获取tripID的IN部分的记录,但是你正在使用派生表计算排名,如果你的内部查询结果集很大,这可能没有多大帮助..

我可能会将它放入一个临时表中并在排名上创建一个索引,因此这对其他联合查询也很有帮助。

还查看了您的执行计划,我可以看到您多次扫描同一个表并每次读取很多行

即使没有数据类型转换警告,您的查询也不会使用您有效拥有的任何索引

【讨论】:

  • 这绝对成功了!创建需要一段时间,但是一旦创建,所有查询都几乎是即时的!谢谢! PS:我只对每个 TripID 查询一次,所以我认为临时表不会有帮助。
  • 很高兴它帮助了你,如果你能提供更多的细节,将来也会有帮助..questions seeking performance help should include DDL,DML Of the tables involved along with test data..if your test data is large,try scripting out schema and stats for the table(right click database-&gt;generate scripts-&gt;select specific database objects-&gt;in next screen select advanced and choose Script statistics) and paste it in question..With this info any one repro the same issue you are facing.Otherwise it becomes very difficult to answer your question .Pasting server version also helps
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多