我们的前端和后端都使用 JSON,并且我们拥有将其完美绑定到前端和后端的模型。因此,完全保留 JSON 格式确实让我作为开发人员的生活变得更轻松,并减少了我对实体框架的需求来满足我的开发需求。然而,从我读过的各种文章来看,使用 For JSON 对性能有轻微影响,但我们有一个包含大约 2500 条记录的查询,大约需要 10-15 秒,感觉我们的查询出了问题。我不得不使用分页来使我们的前端更容易忍受。我们对 SQL 比较陌生(不是程序员,但确实到处使用 sql),所以我们还有很多东西要学习,但这一点非常关键,所以我希望这里有人能够查明我的查询的问题。有人告诉我不要让 SQL Server 处理反序列化和序列化,但说实话,我看到过用户的帖子拥有数万条记录,并且他们的 json 代码运行时间不到一秒,但这对我来说是可以接受的并且完全值得如果可以实现的话,性能会受到影响。请看下面的代码:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date, ,>
-- Description: <Description, ,>
-- =============================================
ALTER FUNCTION [dbo].[A2Q_0171_RR_CertificationReviewModel_Browse_JSON](@StartingIndex int, @MaxRecords int)
RETURNS NVARCHAR(MAX)
AS
BEGIN
RETURN
(
select
(
select
JSON_QUERY ((select
--top (@MaxRecords)
t1.MMCID,
dbo.A2F_0012_ReturnMMCIDforDisplay(t1.MMCID) as MMCIDForDisplay
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER)) as MMCID,
JSON_QUERY ((select distinct
t2.STATE_ID,
t2.ENTITY_NAME,
t2.ENTITY_ABREVIATION,
--t3.PROGRAM_SHORT_NAME as PROGRAM_CONCATENATE,
(select distinct
t4.PROGRAM_NAME_DD,
t5.PROGRAM_NAME,
t5.PROGRAM_SHORT_NAME,
t5.PROGRAM_ACTIVE
from
dbo.RRBaseProgramTBL as t4,
dbo.RRProgramListTBL as t5
where
t2.STATE_ID = t5.STATE_ID
AND t1.MMCID = t4.MMCID
AND t4.PROGRAM_NAME_DD = t5.PROGRAM_DD
FOR JSON PATH) as PROGRAM_INFO
--dbo.A2F_0013_RR_ConcatenateProgramsByMMCID() as t3
--AND t1.MMCID = t3.MMCID
from
dbo.USStateListTBL as t2
where
t1.STATE_ID = t2.STATE_ID
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER)) as STATE_INFORMATION,
JSON_QUERY ((select
t1.OLD_TRACKER_NAME,
t1.NEW_TRACKER_NAME
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER, INCLUDE_NULL_VALUES)) as TRACKER_NAME,
JSON_QUERY ((select
t1.RATING_PERIOD_BEGINS,
format(t1.RATING_PERIOD_BEGINS, 'MM/dd/yyyy') as RATING_PERIOD_BEGINS_FORMATTED,
t1.RATING_PERIOD_ENDS,
format(t1.RATING_PERIOD_ENDS, 'MM/dd/yyyy') as RATING_PERIOD_ENDS_FORMATTED
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER)) as RATING_PERIOD,
JSON_QUERY ((select
t1.CERTIFICATION_DATE,
format(t1.CERTIFICATION_DATE, 'MM/dd/yyyy') as CERTIFICATION_DATE_FORMATTED
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER)) as CERTIFICATION_DATE,
(select distinct
t7.FIRST_NAME,
t7.LAST_NAME,
t7.INTERNAL_USER_NUMBER,
t8.User_Role_Description,
t8.User_Role_Description_abbrev
from
dbo.RRRoleAssignmentMMCIDTBL as t6,
dbo.UsersAccountsTBL as t7,
dbo.UserRoleDefinitionsTBL as t8
where
t1.MMCID = t6.MMCID
AND (t6.JOB_ASSIGNMENT = 1 OR t6.JOB_ASSIGNMENT = 2 OR t6.JOB_ASSIGNMENT = 5)
AND t6.USER_ASSIGNMENT = t7.INTERNAL_USER_NUMBER
AND t6.JOB_ASSIGNMENT = t8.User_Role_Number_DD
FOR JSON PATH, INCLUDE_NULL_VALUES) as RATE_REVIEWERS,
JSON_QUERY((select distinct
--t9.Signing_Actuary as SIGNING_ACTUARY_CONCATENATED,
t9.ACTUARIAL_FIRM_DD,
t10.FIRM_NAME
from
dbo.ActuarySigningTBL as t9,
dbo.ActuarialFirmTBL as t10
where
t1.MMCID = t9.MMCID
AND t9.ACTUARIAL_FIRM_DD = t10.FIRM_DD_NUMBER
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER, INCLUDE_NULL_VALUES)) as ACTUARIAL_FIRM,
(select
(t11.FIRST_NAME + ' ' + t11.LAST_NAME) as NAME,
t11.INTERNAL_USER_NUMBER
from
dbo.ActuarySigningTBL as t16,
dbo.UsersAccountsTBL as t11
where
t1.MMCID = t16.MMCID
AND t16.SIGNING_ACTUARY_DD = t11.INTERNAL_USER_NUMBER
FOR JSON PATH, INCLUDE_NULL_VALUES) as SIGNING_ACTUARY,
JSON_QUERY((select
t1.REVIEW_TYPE_DD,
t12.ReviewTypeDescription
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER)) as REVIEW_TYPE,
JSON_QUERY((select
t13.STATE_SUBMISSION_DATE,
format(t13.STATE_SUBMISSION_DATE, 'MM/dd/yyyy') as STATE_SUBMISSION_DATE_FORMATTED,
t13.DMCP_SUBMISSION_DATE,
format(t13.DMCP_SUBMISSION_DATE, 'MM/dd/yyyy') as DMCP_SUBMISSION_DATE_FORMATTED
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER, INCLUDE_NULL_VALUES)) as SUBMISSION_DATE,
JSON_QUERY((select
t1.ACTUARIAL_REVIEW_STATUS_DD,
t14.DISPLAY,
t13.OACT_MEMO_DATE,
format(t13.OACT_MEMO_DATE, 'MM/dd/yyyy') as OACT_MEMO_DATE_FORMATTED
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER, INCLUDE_NULL_VALUES)) as OACT_REVIEW_STATUS,
JSON_QUERY((select
t1.DMCP_REVIEW_STATUS_DD,
t15.DISPLAY,
t13.DMCP_RECOMMENDATION_DATE,
format(t13.DMCP_RECOMMENDATION_DATE, 'MM/dd/yyyy') as DMCP_RECOMMENDATION_DATE_FORMATTED,
t13.DMCP_RECOMMENDATION_COMMENT
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER, INCLUDE_NULL_VALUES)) as DMCP_REVIEW_STATUS,
JSON_QUERY((select
t13.RISK_MITIGATION,
t13.RATE_RANGES,
t13.REVISED_CERT,
t13.REVISED_CERT_DATE,
format(t13.REVISED_CERT_DATE, 'MM/dd/yyyy') as REVISED_CERT_DATE_FORMATTED
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER, INCLUDE_NULL_VALUES)) as DMCP_ADDITIONAL_INFO
from
dbo.RateReviewBaseTBL as t1,
dbo.RRReviewTypeTBL as t12,
dbo.DMCPAdditionalTrackerInformationTBL as t13,
dbo.ActuarialReviewStatusDisplay_TBL as t14,
dbo.RRDMCPReviewStatusTBL as t15
where
t1.REVIEW_TYPE_DD = t12.ReviewTypeDD
AND t1.MMCID = t13.MMCID
AND t1.ACTUARIAL_REVIEW_STATUS_DD = t14.ACTUARIAL_REVIEW_STATUS_DD
AND t1.DMCP_REVIEW_STATUS_DD = t15.DMCP_REVIEW_STATUS_DD
--AND t1.MMCID >= (select max(t16.MMCID) from
-- (select top (@StartingIndex) MMCID
-- from dbo.RateReviewBaseTBL
-- order by MMCID) as t16)
order by t1.MMCID
OFFSET (@StartingIndex - 1) ROWS
FETCH NEXT @MaxRecords ROWS ONLY
FOR JSON PATH, INCLUDE_NULL_VALUES
) as DATA,
@StartingIndex as STARTING_INDEX,
(select count(MMCID) from dbo.RateReviewBaseTBL) as TOTAL_ROWS,
@MaxRecords as MAX_RECORDS_PER_QUERY
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER, INCLUDE_NULL_VALUES
)
END
GO
如果我应该提供任何其他信息来帮助调试,我很乐意添加它。
有很多事情需要你考虑。
WITHOUT_ARRAY_WRAPPER
)时,这都有效。这允许您删除大部分子查询和 JSON_QUERY
调用。UsersAccountsTBL
的双子查询可能可以以某种方式组合,但我不知道您的架构或要求。CONVERT
,而不是慢速 FORMAT
函数。CREATE OR ALTER FUNCTION dbo.A2Q_0171_RR_CertificationReviewModel_Browse_JSON
(@StartingIndex int, @MaxRecords int)
RETURNS NVARCHAR(MAX)
AS
BEGIN
RETURN
(
select
(
select
rrb.MMCID AS [MMCID.MMCID],
dbo.A2F_0012_ReturnMMCIDforDisplay(rrb.MMCID) as [MMCID.MMCIDForDisplay],
usstate.STATE_ID AS [STATE_INFORMATION.STATE_ID],
usstate.ENTITY_NAME AS [STATE_INFORMATION.ENTITY_NAME],
usstate.ENTITY_ABREVIATION AS [STATE_INFORMATION.ENTITY_ABREVIATION],
(
select distinct
bp.PROGRAM_NAME_DD,
pl.PROGRAM_NAME,
pl.PROGRAM_SHORT_NAME,
pl.PROGRAM_ACTIVE
from
dbo.RRBaseProgramTBL as bp
join
dbo.RRProgramListTBL as pl
ON bp.PROGRAM_NAME_DD = pl.PROGRAM_DD
where
usstate.STATE_ID = pl.STATE_ID
AND rrb.MMCID = bp.MMCID
FOR JSON PATH
) as [STATE_INFORMATION.PROGRAM_INFO],
rrb.OLD_TRACKER_NAME AS [TRACKER_NAME.OLD_TRACKER_NAME],
rrb.NEW_TRACKER_NAME AS [TRACKER_NAME.NEW_TRACKER_NAME],
rrb.RATING_PERIOD_BEGINS AS [RATING_PERIOD.RATING_PERIOD_BEGINS],
convert(date, rrb.RATING_PERIOD_BEGINS, 101) as [RATING_PERIOD.RATING_PERIOD_BEGINS_FORMATTED],
rrb.RATING_PERIOD_ENDS AS [RATING_PERIOD.RATING_PERIOD_ENDS],
convert(date, rrb.RATING_PERIOD_ENDS, 101) as [RATING_PERIOD.RATING_PERIOD_ENDS_FORMATTED],
rrb.CERTIFICATION_DATE AS [CERTIFICATION_DATE.CERTIFICATION_DATE],
convert(date, rrb.CERTIFICATION_DATE, 101) as [CERTIFICATION_DATE.CERTIFICATION_DATE_FORMATTED],
(
select distinct
ua.FIRST_NAME,
ua.LAST_NAME,
ua.INTERNAL_USER_NUMBER,
urd.User_Role_Description,
urd.User_Role_Description_abbrev
from
dbo.RRRoleAssignmentMMCIDTBL as ram
join
dbo.UsersAccountsTBL as ua
on ram.USER_ASSIGNMENT = ua.INTERNAL_USER_NUMBER
join
dbo.UserRoleDefinitionsTBL as urd
on ram.JOB_ASSIGNMENT = urd.User_Role_Number_DD
where
rrb.MMCID = ram.MMCID
AND ram.JOB_ASSIGNMENT IN (1, 2, 5)
FOR JSON PATH, INCLUDE_NULL_VALUES
) as RATE_REVIEWERS,
acts.ACTUARIAL_FIRM_DD AS [ACTUARIAL_FIRM.ACTUARIAL_FIRM_DD],
actf.FIRM_NAME AS [ACTUARIAL_FIRM.FIRM_NAME]
(
select
ua.FIRST_NAME + ' ' + ua.LAST_NAME as NAME,
ua.INTERNAL_USER_NUMBER
from
dbo.ActuarySigningTBL as acts
join
dbo.UsersAccountsTBL as ua
on acts.SIGNING_ACTUARY_DD = ua.INTERNAL_USER_NUMBER
where
rrb.MMCID = acts.MMCID
FOR JSON PATH, INCLUDE_NULL_VALUES
) as SIGNING_ACTUARY,
rrb.REVIEW_TYPE_DD AS [REVIEW_TYPE.REVIEW_TYPE_DD],
rrvt.ReviewTypeDescription AS [REVIEW_TYPE.ReviewTypeDescription]
dati.STATE_SUBMISSION_DATE AS [SUBMISSION_DATE.STATE_SUBMISSION_DATE],
convert(date, dati.STATE_SUBMISSION_DATE, 101) AS [SUBMISSION_DATE.STATE_SUBMISSION_DATE_FORMATTED],
dati.DMCP_SUBMISSION_DATE AS [SUBMISSION_DATE.DMCP_SUBMISSION_DATE],
convert(date, dati.DMCP_SUBMISSION_DATE, 101) AS [SUBMISSION_DATE.DMCP_SUBMISSION_DATE_FORMATTED],
rrb.ACTUARIAL_REVIEW_STATUS_DD AS [OACT_REVIEW_STATUS.ACTUARIAL_REVIEW_STATUS_DD],
arsd.DISPLAY AS [OACT_REVIEW_STATUS.DISPLAY],
dati.OACT_MEMO_DATE AS [OACT_REVIEW_STATUS.OACT_MEMO_DATE].
convert(date, dati.OACT_MEMO_DATE, 101) AS [OACT_REVIEW_STATUS.OACT_MEMO_DATE_FORMATTED],
rrb.DMCP_REVIEW_STATUS_DD AS [DMCP_REVIEW_STATUS.DMCP_REVIEW_STATUS_DD],
rrdrs.DISPLAY AS [DMCP_REVIEW_STATUS.DISPLAY],
dati.DMCP_RECOMMENDATION_DATE AS [DMCP_REVIEW_STATUS.DMCP_RECOMMENDATION_DATE],
convert(date, dati.DMCP_RECOMMENDATION_DATE, 101) AS [DMCP_REVIEW_STATUS.DMCP_RECOMMENDATION_DATE_FORMATTED],
dati.DMCP_RECOMMENDATION_COMMENT AS [DMCP_REVIEW_STATUS.,
dati.RISK_MITIGATION AS [DMCP_ADDITIONAL_INFO.RISK_MITIGATION],
dati.RATE_RANGES AS [DMCP_ADDITIONAL_INFO.RATE_RANGES],
dati.REVISED_CERT AS [DMCP_ADDITIONAL_INFO.REVISED_CERT],
dati.REVISED_CERT_DATE AS [DMCP_ADDITIONAL_INFO.REVISED_CERT_DATE],
convert(date, dati.REVISED_CERT_DATE, 101) AS [DMCP_ADDITIONAL_INFO.REVISED_CERT_DATE_FORMATTED],
from
dbo.RateReviewBaseTBL as rrb
join
dbo.RRReviewTypeTBL as rrvt
on rrb.REVIEW_TYPE_DD = rrvt.ReviewTypeDD
join
dbo.DMCPAdditionalTrackerInformationTBL as dati,
on rrb.MMCID = dati.MMCID
join
dbo.ActuarialReviewStatusDisplay_TBL as arsd,
on rrb.ACTUARIAL_REVIEW_STATUS_DD = arsd.ACTUARIAL_REVIEW_STATUS_DD
join
dbo.RRDMCPReviewStatusTBL as rrdrs
on rrb.DMCP_REVIEW_STATUS_DD = rrdrs.DMCP_REVIEW_STATUS_DD
left join
dbo.USStateListTBL as usstate
on rrb.STATE_ID = usstate.STATE_ID
left join
(
select distinct
acts.ACTUARIAL_FIRM_DD,
actf.FIRM_NAME
from
dbo.ActuarySigningTBL as acts
join
dbo.ActuarialFirmTBL as actf
on acts.ACTUARIAL_FIRM_DD = actf.FIRM_DD_NUMBER
) as ACTUARIAL_FIRM
ON rrb.MMCID = acts.MMCID
order by rrb.MMCID
OFFSET (@StartingIndex - 1) ROWS
FETCH NEXT @MaxRecords ROWS ONLY
FOR JSON PATH, INCLUDE_NULL_VALUES
) as DATA,
@StartingIndex as STARTING_INDEX,
(select count(*) from dbo.RateReviewBaseTBL) as TOTAL_ROWS,
@MaxRecords as MAX_RECORDS_PER_QUERY
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER, INCLUDE_NULL_VALUES
);
END;
DISTINCT
,它们为什么会在那里?您是否收到重复的邮件,如果是,为什么?也许您的连接条件不正确,或者您需要某种行编号解决方案。ORDER BY... OFFSET
分页本身就是一个问题。按行号分页效率非常低,因为您需要扫描所有先前的行。考虑键集分页。