我最近开始在一个大政府组织工作。我研究软件开发已有4年了。在那个时候,我们浏览了基本的旧学校数据库使用和数据库优先设计,我可以写一个基本的查询,但我们没有进入非常复杂的数据库设计。我们更专注于新的技术,如代码优先实体框架和模型优先等。
现在,我所在组织的各种IT政策使得所使用的技术和技术的任何变化或进步都变得不可能。就在今天早上,我得到了一个工作请求,以解决从数据库调用信息的Web应用程序超时的问题。我很快确定网页的代码隐藏是调用一个存储过程,它正在查询一个有超过20万条记录的表,所以我打开它试着看看我是否可以衡量程序的效率。
程序的复杂性超出了我的复制能力,而且几乎太复杂甚至无法理解!我让数据库管理员通过向表添加索引来帮助我,所以我不会在这里要求技术解决方案。接下来,在继续之前,请查看相关存储过程:
CREATE PROCEDURE [dbo].[stp_RandomisationResultCount]
@noOfRows INT,
@subcouncil INT,
@wards VARCHAR(MAX) = NULL,
@suburbs VARCHAR(MAX) = NULL,
@courts VARCHAR(MAX) = NULL,
@skills VARCHAR(MAX) = NULL,
@isDisabled VARCHAR(1) = NULL,
@hasQualification VARCHAR(1) = NULL,
@gender VARCHAR(1) = NULL,
@age INT = NULL
AS
BEGIN
SELECT COUNT(tblJobSeekerDetails.JobSeeker_ID) resultCount
FROM tblJobSeekerDetails LEFT JOIN tbl_lnk_JobSeeker_OtherSkills
ON tblJobSeekerDetails.JobSeeker_ID = tbl_lnk_JobSeeker_OtherSkills.JobSeeker_ID LEFT JOIN tblOtherSkills
ON tbl_lnk_JobSeeker_OtherSkills.OtherSkillsID = tblOtherSkills.OtherSkillsID LEFT JOIN tblJobSeekerEmploymentHistory
ON tblJobSeekerDetails.JobSeeker_ID = tblJobSeekerEmploymentHistory.JobSeekerID
WHERE (tblJobSeekerDetails.SubCouncilID = @subcouncil)
AND ((WardID IN (SELECT s.Item FROM ufn_SplitIntArray(@wards, ',') s)) OR (@wards IS NULL))
AND ((Suburb IN (SELECT s.Item FROM ufn_SplitIntArray(@suburbs, ',') s)) OR (@suburbs IS NULL))
AND ((RoadType IN (SELECT s.Item FROM ufn_SplitIntArray(@courts, ',') s)) OR (@courts IS NULL))
AND ((tblOtherSkills.OtherSkillsID in (SELECT s.Item FROM ufn_SplitIntArray(@skills, ',') s)) OR (@skills IS NULL))
AND ((Disability = @isDisabled) OR (@isDisabled IS NULL))
AND ((HasTertiaryQualification = @hasQualification) OR (@hasQualification IS NULL))
AND ((Gender = @gender) OR (@gender IS NULL))
AND ((ISNUMERIC(IdentityNumber) = 1 AND
IdentityNumber NOT LIKE '%.%' AND
DATEPART(YEAR, GETDATE()) - (CONVERT(INT, '19' + SUBSTRING(IdentityNumber, 1, 2), 100)) = @age) OR (@age IS NULL))
AND (TypeID = 1)--Jobseekers only
AND (tblJobSeekerDetails.IsExcludedFromRandomisation <> 1 OR tblJobSeekerDetails.IsExcludedFromRandomisation IS NULL)--Explicitly excluded jobseekers
AND (tblJobSeekerDetails.JobSeeker_ID not in (SELECT DISTINCT tj.JobSeeker_ID --Exclude Jobseekers as per stipulated exclusion periods
FROM tblJobSeekerDetails tj INNER JOIN tblJobSeekerEmploymentHistory wh
ON tj.JobSeeker_ID = wh.JobSeekerID
WHERE ((DATEDIFF(DAY, wh.DateOfEmploymentFrom, wh.DateOfEmploymentTo) <= 14 AND DATEDIFF(MONTH, wh.DateOfEmploymentTo, GETDATE()) <= 3 ))
OR
((DATEDIFF(DAY, wh.DateOfEmploymentFrom, wh.DateOfEmploymentTo) > 14 AND DATEDIFF(MONTH, wh.DateOfEmploymentTo, GETDATE()) BETWEEN 4 AND 6))
OR
(GETDATE() BETWEEN wh.DateOfEmploymentFrom AND wh.DateOfEmploymentTo)
OR (wh.DateOfEmploymentFrom > GETDATE() OR wh.DateOfEmploymentTo > GETDATE())
GROUP BY tj.JobSeeker_ID))
END
现在,这足以让我害怕。我可以概括地理解它应该做什么,但是目前我不可能做到提高效率。我被要求查看这个问题的唯一原因是因为负责该应用程序的开发人员今天被预订了病假。我的问题是,这是通常用开发人员的sql知识创建的东西,还是用于帮助创建这样可怕的sql的某种工具?
答案 0 :(得分:1)
这看起来像是一个典型的程序。它可能是手工编码的。
该过程似乎是基于许多搜索参数(可能来自应用程序中的搜索表单)进行搜索。
这种查询对于优化器来说通常很难,因为它缺少关键搜索词(或者在不同的调用中有不同的键搜索词)。
此特定查询的最佳优化可能是全表扫描,因此请检查最近是否添加了任何索引并尝试删除它们。请注意,索引可能是由于某种原因而添加的,因此删除索引可能会在应用程序的其他部分引入性能问题。
如果失败,您应该检查查询计划。
答案 1 :(得分:1)
实际上不,这里有严重的问题。
首先,请提供queryp lan。
但第二个 - 需要WITH RECOMPILE提示。此SP具有许多不同的查询路径,具体取决于参数但不表达 - 第一次调用将确定查询路径,无论多么合理。标准(基本知识)方法是向查询添加提示要优化的内容 - 或者让编译器不重用计划,这就是WITH RECOMPILE所做的。
http://technet.microsoft.com/en-us/library/ms181714.aspx
这不是老派 - 抱歉。这种类型的SP在15年前腐烂了。这是任何更高级别的查询框架闪耀的一件事(EF / LINQ是一个,但是,嘿,我在1990年左右使用类似的东西,不是开玩笑,所以不要说“现代”的东西比你学习的编程要长得多)。 SQL - 特别是在SP中 - 很难处理变量查询要求。