情况
当使用包含一组已定义列的 SELECT 语句查询数据库时,大约 21 秒内会收到结果。
, *
如果在定义的列集列表末尾有一个额外的星号 ( ),则查询将在 2 秒内返回结果。
查询执行计划
执行计划有很大不同。
您可以使用 PasteThePlan 中的链接找到好的实际查询执行计划和坏的实际查询执行计划。
列列表中包含 , * 的语句(末尾)
SELECT -- DISTINCT -- 27.04.2020
'SchuelerKlasse' AS EcoQuery,
VX_PERSON.PER_MAN_ID, VX_PERSON.PER_ID, VX_PERSON.PER_NAME, VX_PERSON.PER_VORNAME, VX_PERSON.PER_LB_PER_ID,
VX_PERSON.PER_GESCHLECHT, VX_PERSON.PER_GEBURTSDATUM, VX_PERSON.PER_TELP, VX_PERSON.PER_MAILP, VX_PERSON.PER_NATP, VX_PERSON.PER_VERSICHERTENNUMMER, VX_PERSON.PER_LAND,
VX_ADRESSE.ADR_STRASSE, VX_ADRESSE.ADR_PLZ, VX_ADRESSE.ADR_ORT,
VX_KLASSE.KL_CODE, VX_KLASSE.KL_BEZEICHNUNG,
VX_KLASSEABSCHNITTSCHUELER.KAS_ANMELDE_STATUS,
VX_KLASSEABSCHNITTSCHUELER.KAS_ANMELDETYP, VX_KLASSEABSCHNITTSCHUELER.KAS_ABSCHNITTSNR,
VX_KLASSE_ZEITRAUM.KLZ_IS_ABSCHLUSSKLASSE, VX_KLASSE_ZEITRAUM.KLZ_ZR_NR,
VX_ZEITRAUM.ZR_BEGINN, VX_ZEITRAUM.ZR_ENDE
,'' AS FA_CODE
,'' AS FA_BEZ_STP, '' AS FA_BEZ_STP_LANG
, '' AS EcoOrig_FA_CODE, '' AS EcoOrig_FA_BEZ_STP, '' AS EcoOrig_FA_BEZ_STP_LANG
, VX_ANGEBOT.ANG_BEGINN
,*
FROM
ECOLST.VX_KLASSE_ZEITRAUM,
ECOLST.VX_PERSON,
ECOLST.VX_KLASSE,
ECOLST.VX_KLASSEABSCHNITTSCHUELER,
ECOLST.VX_ZEITRAUM,
ECOLST.VX_ADRESSE
, ECOSYS.T_KLASSE
, ECOLST.VX_ANGEBOT
WHERE
VX_KLASSE_ZEITRAUM.klz_kl_id = VX_KLASSE.kl_id
AND VX_KLASSE_ZEITRAUM.klz_zr_id = VX_ZEITRAUM.zr_id
AND VX_KLASSEABSCHNITTSCHUELER.kas_ang_id = VX_KLASSE.kl_ang_id
AND VX_KLASSEABSCHNITTSCHUELER.kas_zr_id = VX_ZEITRAUM.zr_id
AND VX_KLASSEABSCHNITTSCHUELER.kas_per_id = VX_PERSON.per_id
AND VX_KLASSEABSCHNITTSCHUELER.kas_kl_id = VX_KLASSE.kl_id
AND VX_KLASSEABSCHNITTSCHUELER.KAS_ANMELDE_STATUS LIKE 'De%' -- LIKE 'Definitiv%'
AND VX_PERSON.per_id = VX_ADRESSE.adr_per_id
AND VX_PERSON.per_man_id = VX_KLASSE.kl_man_id
AND VX_KLASSE.KL_ANG_ID = VX_ANGEBOT.ANG_ID
AND VX_KLASSE.KL_MAN_ID = 15
AND VX_KLASSE.KL_ID = T_KLASSE.KL_ID
AND T_KLASSE.KL_STATUS_ID = 491 -- d.h. TS_CODE.CODE_UP_BEZEICHNUNG = 'AKTIV'
AND VX_KLASSE.KL_KLASSENTYP_ID IN (742,743,1235,1926,2075,2076,2078,2079,2080,2081,2086,2103,2118,2119,2122,2152,2252,2308,2416)
AND VX_PERSON.PER_NP = 1 -- Natürliche Person
AND LEN(LTRIM(RTRIM(VX_PERSON.PER_VORNAME))) > 0 -- TRIM() kann erst ab SQL Server 2017 verwendet werden
AND LEN(LTRIM(RTRIM(VX_PERSON.PER_NAME))) > 0 -- TRIM() kann erst ab SQL Server 2017 verwendet werden
AND VX_ZEITRAUM.zr_beginn <= CONVERT(DATETIME, '20.05.2023', 104)
AND VX_ZEITRAUM.zr_ende >= CONVERT(DATETIME, '14.02.2023', 104)
AND VX_PERSON.per_man_id IN ( 15 )
--AND VX_Person.PER_ID IN (233777,233779)
问题
*
一般建议在定义列列表时不要使用,但在我的例子中,, *
在末尾添加到列列表,可以显着加快查询速度。(从 21 秒减少到 2 秒)
实际执行计划中没有缺失索引建议。
, *
我认为这与在语句中使用时返回的特定列有关,这些列可能包含在查询优化器认为有用的索引中,但我不确定如何查明这些列。
为了说服 SQL Server 运行不包含
, *
列列表的执行不佳的语句,使用与包含列列表中的附加项的性能语句类似的计划,我必须创建哪些索引?, *
我是否必须分析良好执行计划中使用的所有索引并创建缩减索引(省略某些列)以便查询优化器考虑对语句使用类似的良好
, *
执行计划而不需要额外的?
根据建议尝试解决方案
OPTION (MIN_GRANT_PERCENT = 10, MAX_GRANT_PERCENT = 15)
应用上述解决方案仅提供了大约 1 小时的临时性能提升。之后查询恢复到错误的执行计划。我不知道为什么...
数据库兼容级别
,*
使用以下命令将数据库的兼容级别向下更改为 110 (SQL Server 2012),导致上述查询的性能不断提高,而无需在列列表中添加。USE [master] GO ALTER DATABASE [ECOWEBBSP] SET COMPATIBILITY_LEVEL = 110 GO
兼容级别为 110 的查询执行计划表明,查询优化器在检索数据时选择了一种完全不同的方法,并且在分配正确的内存量 (110 MB) 方面没有任何问题。
跟进问题
将兼容级别设置为 110 是我唯一的选择吗?
额外反馈
Erik 的回答中提到的Ominous Function是由视图中的fi_kla_is_abschlussklasse
列触发的。基础表在检索数据时调用标量值函数。该函数本身返回 0 或 1,具体取决于学生是在毕业班 (1) 还是不在毕业班 (0)。VX_KLASSE_ZEITRAUM.KLZ_IS_ABSCHLUSSKLASSE
ECOLST.VX_KLASSE_ZEITRAUM
但是,在兼容级别设置为 110 (SQL Server 2012) 的情况下运行时,该函数似乎对查询持续时间的影响不大。有关详细信息,请参阅兼容级别为 110 的查询执行计划。
虽然这两个查询计划有很多差异,但您在较慢的计划中遇到的问题主要发生在溢出操作中,因为内存授予不足:
至少还有一次泄漏,但影响较小。
更快的计划不会溢出的原因是因为它获得了更高的内存授予,SQL Server 根据行数和通过内存消耗运算符(如 Sorts 和 Hashes)的每行的估计大小来估计。
这是内存授予信息:
在这种复杂的查询中很难获得准确的基数估计,但您可以尝试:
OPTION(QUERYTRACEON 9481)
可能值得注意的是,您有一个标量 UDF 抑制此查询的并行性,以及几个可能导致估计值丢失的非 SARGable 谓词。
功能:
查询反模式:
可以简化为寻找单个字符通配符:
或者只是寻找非空字符串: