You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL Server多TVVA表关联查询执行过慢,寻求优化方案

SQL Server查询性能优化求助

我有一条SQL Server查询语句,执行耗时数分钟。最初只关联到TVVA5.VVA_VAL时执行正常,但引入TVVA6后开始变慢,加入TVVA7后更慢,每新增一个TVVA相关列,查询速度就持续下降。测试发现,关联不超过5个TVVA列时执行流畅,求优化思路。

原查询代码:

SELECT 
                [TCRD].[CRD_REQ_ID] AS [requestId],
                [TCTP].[CTP_CDE] AS cardType,
                [TCHD].[CHD_COD_EXT] AS codeCardHolder,
                [TCHD].[CHD_FRST_NAMES] AS firstNames,
                [TCHD].[CHD_INI] AS initials,
                [TCHD].[CHD_PFX_LST_NAME] AS prefixLastName,
                [TCHD].[CHD_LST_NAME] AS lastName,
                [TCHD].[CHD_TTL_PFX] AS titlePrefix,
                [TCHD].[CHD_TTL_SFX] AS titleSuffix,
                [TCHD].[CHD_DOB] dateOfBirth,
                [TCRD].[CRD_VAL_DTE] AS cardExpiryDate,
                [TCRD].[CRD_ISS_DTE] AS cardIssueDate,
                [TCHD].[CHD_NAT_CODE] AS natCode,
                [TCHD].[CGD_GDR_CDE] AS genderCode,

                [TPIC].[PIC_VAL] AS picture,
                [TSIG].[SIG_VAL] AS [signature],

                [TCRD].[CRD_NAME_ON_CARD] AS nameOnCard,
                [TORG].[ORG_CDE] AS organizationCode,
                [TNAT].[NAT_DESC_AR] AS nationalityArabic,
                TORG.ORG_FULL_NAME issuingAuthority,

                TVVA1.VVA_VAL nameArabic,
                TVVA2.VVA_VAL docmentType,
                TVVA3.VVA_VAL docmentNumber,
                TVVA4.VVA_VAL passportNumber,
                TVVA5.VVA_VAL phoneNumber,
                TVVA6.VVA_VAL professionEnglish,
                TVBV1.VBV_VAL passportImage,
                TVVA7.VVA_VAL cardPersonalizationDate,
                TVVA8.VVA_VAL printerSerialNumber,
                TVVA9.VVA_VAL placeOfBirthArabic,
                TVVA10.VVA_VAL addressInQatarArabic,
                TVVA11.VVA_VAL sponsorNameEnglish,
                TVVA12.VVA_VAL sponsorNameArabic,
                TVVA13.VVA_VAL residencyType
            FROM        
                TCHD                
            INNER JOIN
                TCRD
            ON
                [TCHD].[CHD_ID] = [TCRD].[CRD_CHD_ID]
            INNER JOIN
                TCTP
            ON
                [TCRD].[CRD_CTP_ID] = [TCTP].[CTP_ID]
            INNER JOIN
                TNAT
            ON
                [TCHD].[CHD_NAT_CODE] = [TNAT].[NAT_CODE]
            INNER JOIN
                TORG
            ON
                [TCRD].[CRD_ORG_ID] = [TORG].[ORG_ID]
            INNER JOIN
                TPIC                        
                cross apply (select [TPIC].[PIC_VAL] AS '*' for xml path('')) P ([picture])
            ON
                [TCRD].[CRD_ID] = [TPIC].[PIC_CRD_ID]
            INNER JOIN              
                TSIG
                cross apply (select [TSIG].[SIG_VAL] AS '*' for xml path('')) S ([signature])
            ON
                [TCRD].[CRD_ID] = [TSIG].[SIG_CRD_ID]
            INNER JOIN
                TVVA TVVA1
            ON
                TVVA1.VVA_PK_VAL = TCHD.CHD_ID 
            AND
                TVVA1.VVA_DVR_ID = (SELECT TDVR.DVR_ID FROM TDVR WHERE TDVR.DVR_NAME = 'NAME_ARABIC' )
            INNER JOIN
                TVVA TVVA2
            ON
                TVVA2.VVA_PK_VAL = TCHD.CHD_ID 
            AND 
                TVVA2.VVA_DVR_ID = (SELECT TDVR.DVR_ID FROM TDVR WHERE TDVR.DVR_NAME = 'DOCUMENT_TYPE' )
            INNER JOIN
                TVVA TVVA3
            ON
                TVVA3.VVA_PK_VAL = TCHD.CHD_ID
            AND 
                TVVA3.VVA_DVR_ID = (SELECT TDVR.DVR_ID FROM TDVR WHERE TDVR.DVR_NAME = 'DOCUMENT_NUMBER' )
            INNER JOIN
                TVVA TVVA4
            ON
                TVVA4.VVA_PK_VAL = TCHD.CHD_ID
            AND 
                TVVA4.VVA_DVR_ID = (SELECT TDVR.DVR_ID FROM TDVR WHERE TDVR.DVR_NAME = 'PASSPORT_NUMBER' )
            INNER JOIN
                TVVA TVVA5
            ON
                TVVA5.VVA_PK_VAL = TCHD.CHD_ID
            AND 
                TVVA5.VVA_DVR_ID = (SELECT TDVR.DVR_ID FROM TDVR WHERE TDVR.DVR_NAME = 'PHONE_NUMBER' )
            INNER JOIN
                TVVA TVVA6
            ON
                TVVA6.VVA_PK_VAL = TCHD.CHD_ID
            AND 
                TVVA6.VVA_DVR_ID = (SELECT TDVR.DVR_ID FROM TDVR WHERE TDVR.DVR_NAME = 'PROFESSION_ENGLISH' )
            INNER JOIN
                TVVA TVVA7
            ON
                TVVA7.VVA_PK_VAL = TCRD.CRD_ID
            AND 
                TVVA7.VVA_DVR_ID = (SELECT TDVR.DVR_ID FROM TDVR WHERE TDVR.DVR_NAME = 'CARD_PERSONALIZATION_DATE' )
            INNER JOIN
                TVBV TVBV1
                cross apply (select TVBV1.VBV_VAL AS '*' for xml path('')) PP ([passportImage])
            ON
                TVBV1.VBV_PK_VAL = TCHD.CHD_ID      
            AND 
                TVBV1.VBV_DVR_ID = (SELECT TDVR.DVR_ID FROM TDVR WHERE TDVR.DVR_NAME = 'PASSPORT_IMAGE' )
            INNER JOIN
                TVVA TVVA8
            ON
                TVVA8.VVA_PK_VAL = TCRD.CRD_ID
            AND 
                TVVA8.VVA_DVR_ID = (SELECT TDVR.DVR_ID FROM TDVR WHERE TDVR.DVR_NAME = 'PRINTER_SERIAL_NUMBER' )
            INNER JOIN
                TVVA TVVA9
            ON
                TVVA9.VVA_PK_VAL = TCHD.CHD_ID
            AND 
                TVVA9.VVA_DVR_ID = (SELECT TDVR.DVR_ID FROM TDVR WHERE TDVR.DVR_NAME = 'PLACE_OF_BIRTH_ARABIC' )
            INNER JOIN
                TVVA TVVA10
            ON
                TVVA10.VVA_PK_VAL = TCHD.CHD_ID
            AND 
                TVVA10.VVA_DVR_ID = (SELECT TDVR.DVR_ID FROM TDVR WHERE TDVR.DVR_NAME = 'ADDRESS_IN_QATAR_ARABIC' )
            INNER JOIN
                TVVA TVVA11
            ON
                TVVA11.VVA_PK_VAL = TCHD.CHD_ID
            AND 
                TVVA11.VVA_DVR_ID = (SELECT TDVR.DVR_ID FROM TDVR WHERE TDVR.DVR_NAME = 'SPONSOR_NAME_ENGLISH' )
            INNER JOIN
                TVVA TVVA12
            ON
                TVVA12.VVA_PK_VAL = TCHD.CHD_ID
            AND 
                TVVA12.VVA_DVR_ID = (SELECT TDVR.DVR_ID FROM TDVR WHERE TDVR.DVR_NAME = 'SPONSOR_NAME_ARABIC' )
            INNER JOIN
                TVVA TVVA13
            ON
                TVVA13.VVA_PK_VAL = TCHD.CHD_ID
            AND 
                TVVA13.VVA_DVR_ID = (SELECT TDVR.DVR_ID FROM TDVR WHERE TDVR.DVR_NAME = 'RESIDENCY_TYPE' )
            WHERE                                       
                [TCRD].[CRD_REQ_ID] = 10720

优化思路

1. 用条件聚合替换多次TVVA表关联

多次JOIN同一张TVVA表会导致查询计划反复扫描表,性能随关联次数线性下降。改用条件聚合(行转列),只需扫描TVVA表1-2次就能获取所有需要的字段:

SELECT 
    [TCRD].[CRD_REQ_ID] AS [requestId],
    [TCTP].[CTP_CDE] AS cardType,
    [TCHD].[CHD_COD_EXT] AS codeCardHolder,
    [TCHD].[CHD_FRST_NAMES] AS firstNames,
    [TCHD].[CHD_INI] AS initials,
    [TCHD].[CHD_PFX_LST_NAME] AS prefixLastName,
    [TCHD].[CHD_LST_NAME] AS lastName,
    [TCHD].[CHD_TTL_PFX] AS titlePrefix,
    [TCHD].[CHD_TTL_SFX] AS titleSuffix,
    [TCHD].[CHD_DOB] dateOfBirth,
    [TCRD].[CRD_VAL_DTE] AS cardExpiryDate,
    [TCRD].[CRD_ISS_DTE] AS cardIssueDate,
    [TCHD].[CHD_NAT_CODE] AS natCode,
    [TCHD].[CGD_GDR_CDE] AS genderCode,
    [TPIC].[PIC_VAL] AS picture,
    [TSIG].[SIG_VAL] AS [signature],
    [TCRD].[CRD_NAME_ON_CARD] AS nameOnCard,
    [TORG].[ORG_CDE] AS organizationCode,
    [TNAT].[NAT_DESC_AR] AS nationalityArabic,
    TORG.ORG_FULL_NAME issuingAuthority,
    -- 从CHD关联的TVVA聚合结果取字段
    tvva_chd.nameArabic,
    tvva_chd.docmentType,
    tvva_chd.docmentNumber,
    tvva_chd.passportNumber,
    tvva_chd.phoneNumber,
    tvva_chd.professionEnglish,
    tvva_chd.placeOfBirthArabic,
    tvva_chd.addressInQatarArabic,
    tvva_chd.sponsorNameEnglish,
    tvva_chd.sponsorNameArabic,
    tvva_chd.residencyType,
    -- 从CRD关联的TVVA聚合结果取字段
    tvva_crd.cardPersonalizationDate,
    tvva_crd.printerSerialNumber,
    TVBV1.VBV_VAL passportImage
FROM        
    TCHD                
INNER JOIN TCRD ON [TCHD].[CHD_ID] = [TCRD].[CRD_CHD_ID]
INNER JOIN TCTP ON [TCRD].[CRD_CTP_ID] = [TCTP].[CTP_ID]
INNER JOIN TNAT ON [TCHD].[CHD_NAT_CODE] = [TNAT].[NAT_CODE]
INNER JOIN TORG ON [TCRD].[CRD_ORG_ID] = [TORG].[ORG_ID]
INNER JOIN TPIC ON [TCRD].[CRD_ID] = [TPIC].[PIC_CRD_ID]
INNER JOIN TSIG ON [TCRD].[CRD_ID] = [TSIG].[SIG_CRD_ID]
INNER JOIN TVBV TVBV1 
    ON TVBV1.VBV_PK_VAL = TCHD.CHD_ID      
    AND TVBV1.VBV_DVR_ID = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'PASSPORT_IMAGE')
-- 聚合关联CHD_ID的TVVA数据
LEFT JOIN (
    SELECT 
        VVA_PK_VAL,
        MAX(CASE WHEN VVA_DVR_ID = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'NAME_ARABIC') THEN VVA_VAL END) AS nameArabic,
        MAX(CASE WHEN VVA_DVR_ID = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'DOCUMENT_TYPE') THEN VVA_VAL END) AS docmentType,
        MAX(CASE WHEN VVA_DVR_ID = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'DOCUMENT_NUMBER') THEN VVA_VAL END) AS docmentNumber,
        MAX(CASE WHEN VVA_DVR_ID = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'PASSPORT_NUMBER') THEN VVA_VAL END) AS passportNumber,
        MAX(CASE WHEN VVA_DVR_ID = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'PHONE_NUMBER') THEN VVA_VAL END) AS phoneNumber,
        MAX(CASE WHEN VVA_DVR_ID = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'PROFESSION_ENGLISH') THEN VVA_VAL END) AS professionEnglish,
        MAX(CASE WHEN VVA_DVR_ID = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'PLACE_OF_BIRTH_ARABIC') THEN VVA_VAL END) AS placeOfBirthArabic,
        MAX(CASE WHEN VVA_DVR_ID = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'ADDRESS_IN_QATAR_ARABIC') THEN VVA_VAL END) AS addressInQatarArabic,
        MAX(CASE WHEN VVA_DVR_ID = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'SPONSOR_NAME_ENGLISH') THEN VVA_VAL END) AS sponsorNameEnglish,
        MAX(CASE WHEN VVA_DVR_ID = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'SPONSOR_NAME_ARABIC') THEN VVA_VAL END) AS sponsorNameArabic,
        MAX(CASE WHEN VVA_DVR_ID = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'RESIDENCY_TYPE') THEN VVA_VAL END) AS residencyType
    FROM TVVA
    GROUP BY VVA_PK_VAL
) tvva_chd ON tvva_chd.VVA_PK_VAL = TCHD.CHD_ID
-- 聚合关联CRD_ID的TVVA数据
LEFT JOIN (
    SELECT 
        VVA_PK_VAL,
        MAX(CASE WHEN VVA_DVR_ID = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'CARD_PERSONALIZATION_DATE') THEN VVA_VAL END) AS cardPersonalizationDate,
        MAX(CASE WHEN VVA_DVR_ID = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'PRINTER_SERIAL_NUMBER') THEN VVA_VAL END) AS printerSerialNumber
    FROM TVVA
    GROUP BY VVA_PK_VAL
) tvva_crd ON tvva_crd.VVA_PK_VAL = TCRD.CRD_ID
WHERE                                       
    [TCRD].[CRD_REQ_ID] = 10720

2. 预获取DVR_ID,避免重复子查询

原查询每个TVVA关联都执行一次SELECT TDVR.DVR_ID,会重复查询TDVR表。可以提前把需要的DVR_ID存入变量,减少重复查询:

-- 提前定义所有需要的DVR_ID变量
DECLARE @NameArabicId INT = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'NAME_ARABIC');
DECLARE @DocumentTypeId INT = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'DOCUMENT_TYPE');
DECLARE @DocumentNumberId INT = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'DOCUMENT_NUMBER');
DECLARE @PassportNumberId INT = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'PASSPORT_NUMBER');
DECLARE @PhoneNumberId INT = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'PHONE_NUMBER');
DECLARE @ProfessionEnglishId INT = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'PROFESSION_ENGLISH');
DECLARE @CardPersonalizationDateId INT = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'CARD_PERSONALIZATION_DATE');
DECLARE @PrinterSerialNumberId INT = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'PRINTER_SERIAL_NUMBER');
DECLARE @PlaceOfBirthArabicId INT = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'PLACE_OF_BIRTH_ARABIC');
DECLARE @AddressInQatarArabicId INT = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'ADDRESS_IN_QATAR_ARABIC');
DECLARE @SponsorNameEnglishId INT = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'SPONSOR_NAME_ENGLISH');
DECLARE @SponsorNameArabicId INT = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'SPONSOR_NAME_ARABIC');
DECLARE @ResidencyTypeId INT = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'RESIDENCY_TYPE');
DECLARE @PassportImageId INT = (SELECT DVR_ID FROM TDVR WHERE DVR_NAME = 'PASSPORT_IMAGE');

-- 查询中直接使用变量
MAX(CASE WHEN VVA_DVR_ID = @NameArabicId THEN VVA_VAL END) AS nameArabic

3. 添加针对性索引

  • TVVA表创建复合覆盖索引:CREATE NONCLUSTERED INDEX IX_TVVA_PK_DVR ON TVVA(VVA_PK_VAL, VVA_DVR_ID) INCLUDE(VVA_VAL);,让聚合查询无需回表。
  • TVBV表创建复合覆盖索引:CREATE NONCLUSTERED INDEX IX_TVBV_PK_DVR ON TVBV(VBV_PK_VAL, VBV_DVR_ID) INCLUDE(VBV_VAL);
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 15:09:58