存储过程部分优化
Posted
技术标签:
【中文标题】存储过程部分优化【英文标题】:Stored procedure part optimization 【发布时间】:2015-04-30 22:08:30 【问题描述】:我有一个存储过程
CREATE PROCEDURE [dbo].[MyProcedure]
-- Add the parameters for the stored procedure here
@xml XML
AS
BEGIN
SET FMTONLY OFF
declare @idoc INT; -- table(CentreId bigint, LanguageId int)
EXEC sp_xml_preparedocument @idoc OUTPUT, @xml
--declare @LangCentre table (CentreId bigint, LanguageId int)
CREATE TABLE #LangCentre
(
CentreId bigint,
LanguageId INT
)
INSERT into #LangCentre (CentreId, LanguageId)(
SELECT * from OPENXML (@idoc, '/T/R', 2) WITH (CentreId BIGINT 'C', LanguageId int 'L'))
CREATE TABLE #LangCentreCTranslation
(
CentreId BIGINT,
LanguageId INT,
CentreTranslationId BIGINT
)
INSERT into #LangCentreCTranslation (CentreId, LanguageId, CentreTranslationId)(
SELECT
lc.CentreId,
lc.LanguageId,
CASE WHEN ct.id IS NULL THEN ct2.id ELSE ct.id END AS CentreTranslationId
FROM #LangCentre lc
LEFT JOIN dbo.CentreTranslation ct ON ct.centre_id = lc.CentreId AND ct.language_id = lc.LanguageId
LEFT JOIN dbo.CentreTranslation ct2 ON ct2.centre_id = lc.CentreId and ct2.language_id = 1
)
SELECT
lcct.CentreTranslationId,
lcct.LanguageId,
lcct.CentreId AS CentreID ,
ptBusinessCentre.about AS BusinessCentreDescription,
ptBusinessCentre.meta_title AS BusinessCentreMetaTitle,
ptBusinessCentre.meta_keywords AS BusinessCentreMetaKeywords,
ptBusinessCentre.meta_description AS BusinessCentreMetaDescription,
ptOffice.about AS OfficeDescription,
ptOffice.meta_title AS OfficeMetaTitle,
ptOffice.meta_keywords AS OfficeMetaKeywords,
ptOffice.meta_description AS OfficeMetaDescription,
ptVirtualOffice.about AS VirtualOfficeDescription,
ptVirtualOffice.meta_title AS VirtualOfficeMetaTitle,
ptVirtualOffice.meta_keywords AS VirtualOfficeMetaKeywords,
ptVirtualOffice.meta_description AS VirtualOfficeMetaDescription,
ptMeetingRoom.about AS MeetingRoomDescription,
ptMeetingRoom.meta_title AS MeetingRoomMetaTitle,
ptMeetingRoom.meta_keywords AS MeetingRoomMetaKeywords,
ptMeetingRoom.meta_description AS MeetingRoomMetaDescription,
ptBusinessLounge.about AS BusinessLoungeDescription,
ptBusinessLounge.meta_title AS BusinessLoungeMetaTitle,
ptBusinessLounge.meta_keywords AS BusinessLoungeMetaKeywords,
ptBusinessLounge.meta_description AS BusinessLoungeMetaDescription,
ptDayOffice.about AS DayOfficeDescription,
ptDayOffice.meta_title AS DayOfficeMetaTitle,
ptDayOffice.meta_keywords AS DayOfficeMetaKeywords,
ptDayOffice.meta_description AS DayOfficeMetaDescription,
ptVideoConferencing.about AS VideoConferencingDescription,
ptVideoConferencing.meta_title AS VideoConferencingMetaTitle,
ptVideoConferencing.meta_keywords AS VideoConferencingMetaKeywords,
ptVideoConferencing.meta_description AS VideoConferencingMetaDescription,
ptManagedOfficeSolutions.about AS ManagedOfficeSolutionsDescription,
ptManagedOfficeSolutions.meta_title AS ManagedOfficeSolutionsMetaTitle,
ptManagedOfficeSolutions.meta_keywords AS ManagedOfficeSolutionsMetaKeywords,
ptManagedOfficeSolutions.meta_description AS ManagedOfficeSolutionsMetaDescription,
ptTelecommunications.about AS TelecommunicationsDescription,
ptTelecommunications.meta_title AS TelecommunicationsMetaTitle,
ptTelecommunications.meta_keywords AS TelecommunicationsMetaKeywords,
ptTelecommunications.meta_description AS TelecommunicationsMetaDescription,
--
ctContact.manager AS CentreManager,
ctContact.area_director AS AreaDirector,
ctContact.rmm AS RMM,
ctContact.operations_director AS OperationsDirector,
ctContact.financial_controller AS FinancialController,
ctContact.sales_fax_line AS SalesFaxLine,
ctContact.agents_hotline AS AgentsHotline,
ctContact.emergency_phone AS EmergencyPhone,
ctContact.emergency_pager AS EmergencyPager,
ctContact.receptionist_phone AS ReceptionistPhone,
ctContact.rsc_speed_dials AS RscSpeedDials,
ctContact.toll_free AS TollFree,
ctContact.voicemail_server AS VoicemailServer,
ctContact.additional_phone AS AdditionalPhone,
ctContact.additional_fax AS AdditionalFax,
ctContact.centre_manager_email as CentreManagerEmail,
ctContact.area_director_address as AreaDirectorEmail,
ctRooms.number_of_offices AS NumberOfOffices,
ctRooms.number_of_meeting_rooms AS NumberOfMeetingRooms,
ctRooms.number_of_training_rooms AS NumberOfTrainingRooms,
ctRooms.number_of_conference_rooms AS NumberOfConferenceRooms,
ctRooms.number_of_workstations AS NumberOfWorkstations,
ctRooms.number_of_floors AS NumberOfFloors,
ctRooms.number_of_parking_spaces AS NumberOfParkingSpaces,
ctRooms.parking_costs AS ParkingCosts,
ctRooms.floor_area AS FloorArea,
ctRooms.floorplan AS Floorplan,
ctOpeningHours.monday_opening AS MondayOpening,
ctOpeningHours.monday_closing AS MondayClosing,
ctOpeningHours.tuesday_opening AS TuesdayOpening,
ctOpeningHours.tuesday_closing AS TuesdayClosing,
ctOpeningHours.wednesday_opening AS WednesdayOpening,
ctOpeningHours.wednesday_closing AS WednesdayClosing,
ctOpeningHours.thursday_opening AS ThursdayOpening,
ctOpeningHours.thursday_closing AS ThursdayClosing,
ctOpeningHours.friday_opening AS FridayOpening,
ctOpeningHours.friday_closing AS FridayClosing,
ctOpeningHours.saturday_opening AS SaturdayOpening,
ctOpeningHours.saturday_closing AS SaturdayClosing,
ctOpeningHours.sunday_opening AS SundayOpening,
ctOpeningHours.sunday_closing AS SundayClosing,
ctOpeningHours.timezone_id AS TimezoneId,
ctLounge.opening_times_text AS OpeningTimesText,
ctLounge.number_of_armchairs AS NumberOfArmchairs,
ctLounge.number_of_seats_in_library as NumberOfSeatsInLibrary,
ctLounge.number_of_bar_stools as NumberOfBarStools,
ctLounge.number_of_other_seats as NumberOfOtherSeats,
ctLounge.number_of_thinkpods AS NumberOfThinkpods,
ctLounge.number_of_mac_pc_bars AS NumberOfMacPcBars,
ctLounge.number_of_flatscreen_tvs AS NumberOfFlatScreenTvs,
ctLounge.number_of_newspapers AS NumberOfNewspapers,
--
ctLounge.lounge_type as LoungeType,
ctLounge.alternative_to_businesslounge as AlternativeToBL,
ctLounge.last_refubrishment_date as LastRefurbishmentDate,
ctLounge.lounge_location_in_centre as LocationInCentre,
ctLounge.lounge_visible_from_outside as VisibleFromOutside,
ctLounge.signage_to_advertise as SignageOutsideToAdvertise,
ctLounge.reason_for_no_advertisment as ReasonForNoAdvertisement,
ctLounge.type_of_access_control as TypeOfAccessControl,
ctLounge.monday_opening as LoungeMondayOpening,
ctLounge.monday_closing as LoungeMondayClosing,
ctLounge.tuesday_opening as LoungeTuesdayOpening,
ctLounge.tuesday_closing as LoungeTuesdayClosing,
ctLounge.wednesday_opening as LoungeWednesdayOpening,
ctLounge.wednesday_closing as LoungeWednesdayClosing,
ctLounge.thursday_opening as LoungeThursdayOpening,
ctLounge.thursday_closing as LoungeThursdayClosing,
ctLounge.friday_opening as LoungeFridayOpening,
ctLounge.friday_closing as LoungeFridayClosing,
ctLounge.saturday_opening as LoungeSaturdayOpening,
ctLounge.saturday_closing as LoungeSaturdayClosing,
ctLounge.sunday_opening as LoungeSundayOpening,
ctLounge.sunday_closing as LoungeSundayClosing,
ctLounge.type_of_location as TypeOfLocation,
ctLounge.parking_facilities as ParkingFacilities,
ctLounge.have_to_pass_through_security as HaveToPassThroughSecurity,
ctLounge.is_advanced_security_notification_requiered as IsAdvancedSecurityNotificationRequiered,
ctLounge.business_lounge_floor as BusinessLoungeFloor,
ctLounge.type_of_room as TypeOfRoom,
ctLounge.suitable_for_disabled as SuitableForDisabled,
ctLounge.does_directly_receive_light as DoesDirectlyReceiveLight,
ctLounge.airconditioning as Airconditioning,
ctLounge.is_wifi_available as IsWifiAvailable,
ctLounge.is_ethernet_available as IsEthernetAvailable,
ctLounge.number_of_computers as NumberOfComputers,
ctLounge.other_internet_access as OtherInternetAccess,
ctLounge.are_beverages_available as AreBeveragesAvailable,
ctLounge.type_of_coffee_available as TypeOfCoffeeAvailable,
ctLounge.copy_fax_print_facilities as CopyFaxPrintFacilities,
ctLounge.business_support as BusinessSupport,
ctLounge.mobile_charging_points as MobileChargingPoints,
ctLounge.newspapers_and_magazines as NewspapersAndMagazines,
ctLounge.bathroom_facilities_available as BathroomFacilitiesAvailable,
ctLounge.showers_available as ShowersAvailable,
(case
when ctLounge.grade=1 then 'Grade A'
when ctLounge.grade=2 then 'Grade B'
when ctLounge.grade=3 then 'Grade C'
when ctLounge.grade=4 then 'Ungraded'
else 'No Value' end) as Grade,
--
ctOtherInfo.bank_name AS BankName,
ctOtherInfo.bank_address AS BankAddress,
ctOtherInfo.bank_account_number AS BankAccountNumber,
ctOtherInfo.bank_sort_code AS BankSortCode,
ctOtherInfo.bank_swift_code AS BankSwiftCode,
ctOtherInfo.vc_equipment AS VcEquipment,
ctOtherInfo.vc_equipment_working AS VcEquipmentWorking,
ctOtherInfo.isdn AS ISDN,
ctOtherInfo.vc_contact AS VcContact,
ctOtherInfo.vc_phone AS VcPhone,
ctOtherInfo.equipment_make AS EquipmentMake,
ctOtherInfo.speed AS Speed,
ctOtherInfo.additional_charges AS AdditionalCharges,
ctOtherInfo.room_capacity AS RoomCapacity,
ctOtherInfo.out_of_hours_vc_contact AS OutOfHoursVcContact,
ctOtherInfo.vc_room_names AS VcRoomNames,
ctOtherInfo.maximum_bandwidth AS MaximumBandwidth,
ctOtherInfo.floodgate_installed AS FloodgateInstalled,
ctOtherInfo.encryption AS Encryption,
ctOtherInfo.underfloor_cat5_cabling AS UnderfloorCat5Cabling,
ctOtherInfo.lockable_comms_rack_space AS LockableCommsRackSpace,
isNULL(ct.name, cn.name) as CentreName,
ct.name as TranslatedName,
ct.address_line_1 as Address1,
ct.address_line_2 as Address2,
ct.address_line_3 as Address3,
ct.city as Town,
ct.postcode as PostalCode,
ct.country as Country,
ct.county as State,
cn.number as Number,
cn.url as Url,
cn.virtual_tour_url as VirtualTourUrl,
(CASE WHEN status.cnt>0 THEN 1 ELSE 0 END) AS ShowCentre,
cnInactivityReason.[description] as ReasonForNotShowing,
cn.alternate_name as AlternateName,
cn.date_opened as OpeningDate,
cn.closed as Closed,
cn.date_closed as DateClosed,
cn.phone as Phone,
cn.fax as Fax,
cn.email as Email,
cn.position.Lat as Latitude,
cn.position.Long as Longtitude,
images.cnt as ImagesCount,
cn.area as Area,
cn.sales_cluster as SalesCluster,
cn.is_additionl_security_check_required as AdditionalSecurityCheck,
ct.country as TranslatedCountry,
cn.virtual_tour as VirtualTour,
ct.about as OriginalDescription,
ct.directions as directions,
cn.centre_profile_id as CentreProfileId,
ct.amenities as AmenitiesFreeText,
STUFF((SELECT ',' + convert(VARCHAR(10), feature_id) FROM dbo.CentreFeature cf LEFT JOIN #LangCentreCTranslation lcct ON cf.Centre_Id = lcct.Centreid ORDER BY feature_id FOR XML PATH('')), 1, 1, '') as FeatureIds,
STUFF((SELECT ',' + convert(VARCHAR(10), brand_id) FROM dbo.CentreBrand cf LEFT JOIN #LangCentreCTranslation lcct ON cf.Centre_Id = lcct.Centreid ORDER BY brand_id FOR XML PATH('')), 1, 1, '') as BrandIds
FROM #LangCentreCTranslation lcct
INNER JOIN dbo.Centre cn on lcct.CentreId = cn.id
LEFT JOIN dbo.CentreTranslation ct ON lcct.CentreTranslationId = ct.id
LEFT JOIN dbo.ProductTranslation ptBusinessCentre ON lcct.CentreTranslationId = ptBusinessCentre.centre_translation_id AND ptBusinessCentre.product_id = 1
LEFT JOIN dbo.ProductTranslation ptOffice ON lcct.CentreTranslationId = ptOffice.centre_translation_id AND ptOffice.product_id = 2
LEFT JOIN dbo.ProductTranslation ptVirtualOffice ON lcct.CentreTranslationId = ptVirtualOffice.centre_translation_id AND ptVirtualOffice.product_id = 3
LEFT JOIN dbo.ProductTranslation ptMeetingRoom ON lcct.CentreTranslationId = ptMeetingRoom.centre_translation_id AND ptMeetingRoom.product_id = 4
LEFT JOIN dbo.ProductTranslation ptBusinessLounge ON lcct.CentreTranslationId = ptBusinessLounge.centre_translation_id AND ptBusinessLounge.product_id = 5
LEFT JOIN dbo.ProductTranslation ptDayOffice ON lcct.CentreTranslationId = ptDayOffice.centre_translation_id AND ptDayOffice.product_id = 6
LEFT JOIN dbo.ProductTranslation ptVideoConferencing ON lcct.CentreTranslationId = ptVideoConferencing.centre_translation_id AND ptVideoConferencing.product_id = 11
LEFT JOIN dbo.ProductTranslation ptTelecommunications ON lcct.CentreTranslationId = ptTelecommunications.centre_translation_id AND ptTelecommunications.product_id = 12
LEFT JOIN dbo.ProductTranslation ptManagedOfficeSolutions ON lcct.CentreTranslationId = ptManagedOfficeSolutions.centre_translation_id AND ptManagedOfficeSolutions.product_id = 14
LEFT JOIN dbo.CentreContact ctContact ON lcct.CentreId = ctContact.centre_id
LEFT JOIN dbo.CentreRooms ctRooms ON lcct.CentreId = ctRooms.centre_id
LEFT JOIN dbo.CentreOpeningHours ctOpeningHours ON lcct.CentreId = ctOpeningHours.centre_id
LEFT JOIN dbo.CentreLounge ctLounge ON lcct.CentreId = ctLounge.centre_id
LEFT JOIN dbo.CentreOtherInfo ctOtherInfo ON lcct.CentreId = ctOtherInfo.centre_id
LEFT JOIN (SELECT centre_id, COUNT (*) as cnt from dbo.CentreStatus GROUP BY centre_id) status ON status.centre_id=lcct.CentreId
LEFT JOIN dbo.CentreInactivityReason cnInactivityReason ON cn.inactivity_reason = cnInactivityReason.id
LEFT JOIN (SELECT centre_id, COUNT (*) as cnt from dbo.Image2Centre GROUP BY centre_id) images ON images.centre_id=lcct.CentreId
ORDER BY isNULL(ct.name, cn.name)
DROP TABLE #LangCentreCTranslation
DROP TABLE #LangCentre
EXEC sp_xml_removedocument @idoc
-- Insert statements for procedure here
END
SP 处理大约 2700 条记录。这个 SP 的问题是,如果我不禁用
STUFF((SELECT ',' + convert(VARCHAR(10), feature_id) FROM dbo.CentreFeature cf LEFT JOIN #LangCentreCTranslation lcct ON cf.Centre_Id = lcct.Centreid ORDER BY feature_id FOR XML PATH('')), 1, 1, '') as FeatureIds,
STUFF((SELECT ',' + convert(VARCHAR(10), brand_id) FROM dbo.CentreBrand cf LEFT JOIN #LangCentreCTranslation lcct ON cf.Centre_Id = lcct.Centreid ORDER BY brand_id FOR XML PATH('')), 1, 1, '') as BrandIds
此 SP 将在约 13 分钟内执行,但上述行已注释\删除后,它将在约 30 秒内执行,我如何优化 SP 的这些特定部分以提高其性能。如果需要,我可以提供表结构\执行计划(虽然不知道如何附加文件)。任何帮助表示赞赏。
【问题讨论】:
您使用的是什么版本的 SQL Server? Microsoft SQL Server 2008 R2 (SP2) 如果我错了,请纠正我:结果的每一行中的列 FeatureIds 和 BrandIds 是否不同? 它们链接到一个表(特征、品牌),但对于每个中心,它们可能不同(中心 1 的特征:1、2、3、5;中心 2 的特征:1、3、5、 7...) 在我看来表达式“STUFF((SELECT ',' + convert(VARCHAR(10), cf.FeatureId) FROM #CnFeatures cf ORDER BY cf.FeatureId FOR XML PATH('') ), 1, 1, )" 生成 #CnFeatures 中所有 FeatureId 的逗号分隔列表,与查询中的任何其他内容无关。我错了吗? 【参考方案1】:如果您查看以下 2 行,您会注意到它们独立于父查询。
STUFF((SELECT ',' + convert(VARCHAR(10), feature_id)
FROM dbo.CentreFeature cf
LEFT JOIN #LangCentreCTranslation lcct
ON cf.Centre_Id = lcct.Centreid ORDER BY feature_id FOR XML PATH('')), 1, 1, '') as FeatureIds,
和
STUFF((SELECT ',' + convert(VARCHAR(10), brand_id)
FROM dbo.CentreBrand cf
LEFT JOIN #LangCentreCTranslation lcct
ON cf.Centre_Id = lcct.Centreid ORDER BY brand_id FOR XML PATH('')), 1, 1, '') as BrandIds
这些查询不会引用父查询中的任何列。如果这是您想要的,您可以创建两个变量并从这些查询中分配值,并在最终的SELECT
中使用这些变量。
我假设您正在尝试完成类似的事情。
STUFF((SELECT ',' + convert(VARCHAR(10), feature_id)
FROM dbo.CentreFeature cf
WHERE cf.Centre_Id = lcct.Centreid ORDER BY feature_id FOR XML PATH('')), 1, 1, '') as FeatureIds,
和
STUFF((SELECT ',' + convert(VARCHAR(10), brand_id)
FROM dbo.CentreBrand cf
WHERE cf.Centre_Id = lcct.Centreid ORDER BY brand_id FOR XML PATH('')), 1, 1, '') as BrandIds
请注意,我已删除 JOIN
并添加了一个 WHERE
子句以从父查询中引用 lcct.Centreid
的值,并使此子查询成为一个共同相关的子查询。
您也可以选择在将数据插入#LangCentreCTranslation
时执行此操作
INSERT into #LangCentreCTranslation (CentreId, LanguageId, CentreTranslationId,BrandIds,FeatureIds)(
SELECT
lc.CentreId,
lc.LanguageId,
CASE WHEN ct.id IS NULL THEN ct2.id ELSE ct.id END AS CentreTranslationId,
STUFF((SELECT ',' + convert(VARCHAR(10), brand_id) FROM dbo.CentreBrand cf WHERE cf.Centre_Id = lc.Centreid ORDER BY brand_id FOR XML PATH('')), 1, 1, '') as BrandIds,
STUFF((SELECT ',' + convert(VARCHAR(10), feature_id) FROM dbo.CentreFeature cf WHERE cf.Centre_Id = lc.Centreid ORDER BY feature_id FOR XML PATH('')), 1, 1, '') as FeatureIds
FROM #LangCentre lc
LEFT JOIN dbo.CentreTranslation ct ON ct.centre_id = lc.CentreId AND ct.language_id = lc.LanguageId
LEFT JOIN dbo.CentreTranslation ct2 ON ct2.centre_id = lc.CentreId and ct2.language_id = 1
)
【讨论】:
这太棒了,现在性能差不多了。 2700 行 33 秒,非常感谢以上是关于存储过程部分优化的主要内容,如果未能解决你的问题,请参考以下文章