Kev*_*sko 8 performance sql-server sql-server-2012 nonclustered-index query-performance
我有一个 SQL Server 2012 数据库,用于保存已处理文件中的数据。我们从一个文件夹中读取数据,用 python 处理它并将结果保存到数据库中。
我们在 ETL 过程中做的第一件事就是检查文件是否已经被处理。我们简单地做一个:
SELECT id FROM table1 WHERE basename = <basename>
Run Code Online (Sandbox Code Playgroud)
如果有结果我们跳过文件,如果没有结果我们处理文件。现在这个查询需要约 250 毫秒,记录约 5 万。我们已经在basename列上有一个非聚集索引。
我们将看到每个月添加大约 100-200k 条记录。我们批量获取文件。所以我们可能会看到 2k 文件,然后 2 小时后又是 2k 文件。有时我们会得到 10k 文件,有时我们可能只会得到 4k 文件。
保持所有其他变量相同,除了向表中插入 15-2000 万条记录并查看会发生什么之外,还有一个经验法则可以预测我们何时可能遇到性能(查询时间超过 1 秒)问题?
表 DDL:
CREATE TABLE [dbo].[raw_records](
[id] [int] IDENTITY(1,1) NOT NULL,
[basename] [varchar](512) NULL,
[filename] [varchar](1024) NULL,
[file_size] [int] NULL,
[machine] [varchar](10) NULL,
[insert_timestamp] [datetime] NULL,
[raw_xml] [xml] NULL,
[process_status] [varchar](2048) NULL,
PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)
指数:
CREATE NONCLUSTERED INDEX [basename_index] ON [dbo].[raw_records]
(
[basename] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
Run Code Online (Sandbox Code Playgroud)
这个表是在我开始研究它之前很久就创建的,所以我假设有人刚刚制作了filename1024 的最大长度来容纳“足够”。当然是多变的。
生成的文件在文件名本身中具有时间戳和唯一信息(例如system1_metadata_timestamp.xml)一个“系统”无法生成(或不应该)生成具有相同时间戳的文件。
select max(len(basename)), max(len(filename)) from dbo.raw_records;
Run Code Online (Sandbox Code Playgroud)
返回:basename- 143,filename- 168。 将其更改为最大 260 可能是件好事。
process_status可能也不需要那么长,但我觉得猜测是合理的,因为该列用于保存处理阶段的错误消息。我对其进行了查询,最多有 600 个字符。不过,我们通常不会查询该列。它只是用于调试的更多信息。
我正在通过应用程序清理诸如此类的东西。在某些地方我无法摆脱它,但不幸的是在其他地方不能做太多(例如,需要实际检索 XML 列以从中提取数据)。这个问题只是源于看到有问题的查询的性能并且不希望它离开我。这是为每个文件完成的第一件事,所以如果这不起作用,其他任何事情也不会。
Han*_*non 14
有了一个好的索引,定位匹配行所花费的时间应该大致以对数方式缩放,只要您在内存中为索引留出空间。
我会制作索引,UNIQUE因为基本名称必须是唯一的,否则您的工作流程无效,并且它使索引更有效。
CREATE UNIQUE INDEX IX_raw_records_basename
ON dbo.raw_records (basename);
Run Code Online (Sandbox Code Playgroud)
检查查询的执行计划以确保正在使用索引。
确保您有足够的内存空间用于索引,并且假设并发不会成为一个大问题,那么您应该适合大量行。
我会重新考虑basename和filename列的长度,因为查询优化器在计算需要分配多少内存来运行查询时将使用该长度。例如,如果该basename列永远不会包含超过 20 个字符,但您将其定义为 512 个字符,则授予的内存SELECT basename FROM dbo.raw_records;将是实际需要的 25.6 倍。列的长度实际上比大多数人意识到的要重要得多。
您还可以将查询更改为SELECT 1 FROM table1 WHERE basename = <basename>您甚至不需要的方式,id因为您要做的就是验证它的存在。只做你真正需要的。看起来您在问题中显示的索引可以正常工作。
此外,如果空间是一个问题,您可能需要考虑对索引和表进行数据压缩。这应该允许索引适合较小的内存占用。评估DATA_COMPRESSION = ROW与DATA_COMPRESSION = PAGE查看哪种是最适合您的要求的压缩方法。
| 归档时间: |
|
| 查看次数: |
950 次 |
| 最近记录: |