关于优化使用视图的存储过程的速度的建议
Posted
技术标签:
【中文标题】关于优化使用视图的存储过程的速度的建议【英文标题】:Advice on optimizing speed for a Stored Procedure that uses Views 【发布时间】:2010-04-13 10:08:15 【问题描述】:基于以前的question 并在Damir Sudarevic 的大量帮助下(谢谢)我有以下 sql 代码,它工作得很好,但速度很慢。谁能建议我如何加快速度并优化速度。
我现在使用的是 SQL Server Express 2008(根据我最初的问题,不是 2005)。
此代码的作用是从多个表中检索参数及其相关值,并以易于比较的形式旋转表。它非常适合两行数据之一,但现在我正在测试 100 行并运行 GetJobParameters 需要 7 多分钟才能完成?
任何建议都非常感谢,在此先感谢您。
/***********************************************************************************************
** CREATE A VIEW (VIRTUAL TABLE) TO ALLOW EASIER RETREIVAL OF PARMETERS
************************************************************************************************/
CREATE VIEW dbo.vParameters AS
SELECT m.MachineID AS [Machine ID]
,j.JobID AS [Job ID]
,p.ParamID AS [Param ID]
,t.ParamTypeID AS [Param Type ID]
,m.Name AS [Machine Name]
,j.Name AS [Job Name]
,t.Name AS [Param Type Name]
,t.JobDataType AS [Job DataType]
,x.Value AS [Measurement Value]
,x.Unit AS [Unit]
,y.Value AS [JobDataType]
FROM dbo.Machines AS m
JOIN dbo.JobFiles AS j ON j.MachineID = m.MachineID
JOIN dbo.JobParams AS p ON p.JobFileID = j.JobID
JOIN dbo.JobParamType AS t ON t.ParamTypeID = p.ParamTypeID
LEFT JOIN dbo.JobMeasurement AS x ON x.ParamID = p.ParamID
LEFT JOIN dbo.JobTrait AS y ON y.ParamID = p.ParamID
GO
-- Step 2
CREATE VIEW dbo.vJobValues AS
SELECT [Job Name]
,[Param Type Name]
,COALESCE(cast([Measurement Value] AS varchar(50)), [JobDataType]) AS [Val]
FROM dbo.vParameters
GO
/***********************************************************************************************
** GET JOB PARMETERS FROM THE VIEW JUST CREATED
************************************************************************************************/
CREATE PROCEDURE GetJobParameters
AS
-- Step 3
DECLARE @Params TABLE (
id int IDENTITY (1,1)
,ParamName varchar(50)
);
INSERT INTO @Params (ParamName)
SELECT DISTINCT [Name]
FROM dbo.JobParamType
-- Step 4
DECLARE @qw TABLE(
id int IDENTITY (1,1)
, txt nchar(300)
)
INSERT INTO @qw (txt)
SELECT 'SELECT' UNION
SELECT '[Job Name]' ;
INSERT INTO @qw (txt)
SELECT ',MAX(CASE [Param Type Name] WHEN ''' + ParamName
+ ''' THEN Val ELSE NULL END) AS [' + ParamName + ']'
FROM @Params
ORDER BY id;
INSERT INTO @qw (txt)
SELECT 'FROM dbo.vJobValues' UNION
SELECT 'GROUP BY [Job Name]' UNION
SELECT 'ORDER BY [Job Name]';
-- Step 5
--SELECT txt FROM @qw
DECLARE @sql_output VARCHAR (MAX)
SET @sql_output = '' -- NULL + '' = NULL, so we need to have a seed
SELECT @sql_output = -- string to avoid losing the first line.
COALESCE (@sql_output + txt + char (10), '')
FROM @qw
EXEC (@sql_output)
GO
@sql_output 的输出:
SELECT
[Job Name]
,MAX(CASE [Param Type Name] WHEN '001' THEN Val ELSE NULL END) AS [001]
,MAX(CASE [Param Type Name] WHEN '002' THEN Val ELSE NULL END) AS [002]
,MAX(CASE [Param Type Name] WHEN '003' THEN Val ELSE NULL END) AS [003]
,MAX(CASE [Param Type Name] WHEN '004' THEN Val ELSE NULL END) AS [004]
,MAX(CASE [Param Type Name] WHEN '005' THEN Val ELSE NULL END) AS [005]
,MAX(CASE [Param Type Name] WHEN '006' THEN Val ELSE NULL END) AS [006]
,MAX(CASE [Param Type Name] WHEN '007' THEN Val ELSE NULL END) AS [007]
,MAX(CASE [Param Type Name] WHEN '008' THEN Val ELSE NULL END) AS [008]
,MAX(CASE [Param Type Name] WHEN '009' THEN Val ELSE NULL END) AS [009]
,MAX(CASE [Param Type Name] WHEN '010' THEN Val ELSE NULL END) AS [010]
,MAX(CASE [Param Type Name] WHEN '011' THEN Val ELSE NULL END) AS [011]
,MAX(CASE [Param Type Name] WHEN '012' THEN Val ELSE NULL END) AS [012]
,MAX(CASE [Param Type Name] WHEN '013' THEN Val ELSE NULL END) AS [013]
,MAX(CASE [Param Type Name] WHEN '014' THEN Val ELSE NULL END) AS [014]
,MAX(CASE [Param Type Name] WHEN '015' THEN Val ELSE NULL END) AS [015]
,MAX(CASE [Param Type Name] WHEN '016' THEN Val ELSE NULL END) AS [016]
,MAX(CASE [Param Type Name] WHEN 'Acceptance' THEN Val ELSE NULL END) AS [Acceptance]
,MAX(CASE [Param Type Name] WHEN 'AdditionalOptionsAperture1' THEN Val ELSE NULL END) AS [AdditionalOptionsAperture1]
,MAX(CASE [Param Type Name] WHEN 'AdditionalOptionsAperture2' THEN Val ELSE NULL END) AS [AdditionalOptionsAperture2]
,MAX(CASE [Param Type Name] WHEN 'AdditionalOptionsBarcode' THEN Val ELSE NULL END) AS [AdditionalOptionsBarcode]
,MAX(CASE [Param Type Name] WHEN 'AdditionalOptionsFiducial1' THEN Val ELSE NULL END) AS [AdditionalOptionsFiducial1]
,MAX(CASE [Param Type Name] WHEN 'AdditionalOptionsFiducial2' THEN Val ELSE NULL END) AS [AdditionalOptionsFiducial2]
,MAX(CASE [Param Type Name] WHEN 'AlignsFirstPcb' THEN Val ELSE NULL END) AS [AlignsFirstPcb]
,MAX(CASE [Param Type Name] WHEN 'Aperture1DefinedX' THEN Val ELSE NULL END) AS [Aperture1DefinedX]
,MAX(CASE [Param Type Name] WHEN 'Aperture1DefinedY' THEN Val ELSE NULL END) AS [Aperture1DefinedY]
还有另外 200 行...
这是架构:
CREATE TABLE Machines (
MachineID UNIQUEIDENTIFIER PRIMARY KEY,
PrinterType NVARCHAR(255), --UNIQUEIDENTIFIER REFERENCES PrinterTypes(TypeId),
Name NVARCHAR(255),
[Desc] NVARCHAR(MAX),
HostName NVARCHAR(255),
IP NVARCHAR(64), -- allows IPv4 and IPv6
Serial NVARCHAR(10),
Location NVARCHAR(255) )
GO
CREATE TABLE JobFiles (
JobID UNIQUEIDENTIFIER PRIMARY KEY,
MachineID UNIQUEIDENTIFIER REFERENCES Machines(MachineID) ON DELETE CASCADE,
[Desc] NVARCHAR(MAX),
Name NVARCHAR(255),
JobOpen BIT,
[CreateDate] DATETIME ,
[ModifyDate] DATETIME ,
[CreatedByUser] NVARCHAR(64) ,
[ModifiedByUser] NVARCHAR(64) )
GO
CREATE TABLE JobParamType (
ParamTypeID UNIQUEIDENTIFIER PRIMARY KEY,
Name NVARCHAR(255),
[Desc] NVARCHAR(MAX),
JobDataType INT)
GO
CREATE TABLE JobParamGroup (
ParamGroupID UNIQUEIDENTIFIER PRIMARY KEY,
Name NVARCHAR(255),
[Desc] NVARCHAR(MAX))
GO
CREATE TABLE JobParams (
ParamID UNIQUEIDENTIFIER PRIMARY KEY,
ParamTypeID UNIQUEIDENTIFIER REFERENCES JobParamType(ParamTypeID) ON DELETE CASCADE,
ParamGroupID UNIQUEIDENTIFIER REFERENCES JobParamGroup(ParamGroupID) ON DELETE CASCADE,
JobFileID UNIQUEIDENTIFIER REFERENCES JobFiles(JobID) ON DELETE CASCADE,
IsEnabled BIT)
GO
-- Text based property
CREATE TABLE JobTrait (
ParamID UNIQUEIDENTIFIER PRIMARY KEY REFERENCES JobParams(ParamID) ON DELETE CASCADE,
Value NVARCHAR(MAX) )
GO
-- Numeric based property
CREATE TABLE JobMeasurement (
ParamID UNIQUEIDENTIFIER PRIMARY KEY REFERENCES JobParams(ParamID) ON DELETE CASCADE,
Value FLOAT,
Format NVARCHAR(20),
Unit NVARCHAR(MAX) )
【问题讨论】:
您能发布@sql_output 包含的内容吗?你看过执行计划吗? 我添加了 SQL Studio 管理器允许我在运行“Print @sql_output”而不是“EXEC (@sql_output)”时查看的内容。 你能告诉我你所说的执行计划是什么意思吗?我是 sql 新手,学习曲线陡峭...谢谢。 在查询分析器中,打开查询菜单并检查包括实际执行计划。不过,看看你的@sql_output,我并不感到惊讶它需要很长时间。我怀疑任何索引都能够加快这一速度,但可以肯定的是,请仔细查看计划并尝试通过创建适当的索引来至少解决每个表扫描。 另外,你也可以在 from 子句之后发布所有内容吗? (无需包含另外 200 列,但 from 和 where 子句可能会提供更多信息)。 【参考方案1】:好吧,如果不深入了解您的数据库架构设计的细节,我的第一个问题是您是否为视图定义中使用的每个连接谓词创建了索引?
回应你们的cmets.....
非性能调优数据库的典型起点是:
-
在每个表上创建聚集索引,通常在主键上。
在所有外键上创建非聚集索引,因为这些索引可能会在 T-SQL 连接子句中使用。
如果您的数据库没有基本的索引策略,您的大部分查询将执行表扫描(即,表中的每一行都被触及),这是一件坏事.....
有关 SQL Server 索引的出色而简短的介绍,我建议您阅读Brad's Sure Guide to Indexes
【讨论】:
我设置了主键,但这可能还不够。我已修改我的问题以包含架构和输出。 谢谢,为我的外键添加索引将速度从 7 分半钟提高到 2 秒!!!太好了,谢谢。 @Belliez:另外,不要忘记制定索引维护策略,以确保索引提供最佳性能。以上是关于关于优化使用视图的存储过程的速度的建议的主要内容,如果未能解决你的问题,请参考以下文章