Làm thế nào để kiểm tra nếu XML = '' trong máy chủ sql?


7

Tôi đang làm việc với máy chủ sql 2005 và tôi đã gặp tình huống có thể truyền nhiều giá trị trong một tham số.

Dựa trên điều này: Truyền nhiều giá trị cho một tham số SQL , quy trình này sử dụng XML làm tham số.

đây là mã của thủ tục được lưu trữ:

CREATE PROCEDURE [DENORMV2].[udpProductBulletPointSelectByTier1NoteTypeCode] (  
    @Tier1 VARCHAR(10),  
    @LanguageID INT,  
    @SeasonItemID VARCHAR(5) = NULL,
    @ListNoteTypeCode XML,  
    @CacheDuration INT OUTPUT )  
    WITH EXECUTE AS 'webUserWithRW'  
AS

        SELECT  pbp.Tier1, pbp.LanguageId, pbp.NoteText, pbp.NoteTypeCode,  
                pbp.NoteGroup, pbp.SortOrder  
        FROM    dbo.ProductBulletPoint pbp  

        WHERE   Tier1 = @Tier1 
          AND   LanguageId = @LanguageID 
          AND   (      SeasonItemId = @SeasonItemID  
                  OR
                       @SeasonItemID is null
                )

          AND pbp.NoteTypeCode IN (

                 SELECT  NoteTypeCode=BulletPoint.NoteTypeCode.value('./text()[1]', 'varchar(50)')
                   FROM  @ListNoteTypeCode.nodes('/BulletPoint/NoteTypeCode') AS BulletPoint ( NoteTypeCode )

          )

SELECT  @CacheDuration = Duration  
FROM    dbo.CacheDuration  
WHERE   [Key] = 'Product'
GO

Thông tin thêm về thủ tục này tại đây

đây là một ví dụ về cách nó có thể được gọi là:

declare @p5 int  set @p5=86400 
exec DenormV2.udpProductBulletPointSelectByTier1NoteTypeCode
@Tier1=N'WW099',
@LanguageID=3,
@SeasonItemID=N'16AUT',
@ListNoteTypeCode=N'<BulletPoint><NoteTypeCode>GarmentComposition</NoteTypeCode><NoteTypeCode>FootwearAccessoryComposition</NoteTypeCode></BulletPoint>',
@CacheDuration=@p5 output  select @p5

Câu hỏi:

cách tốt nhất để tìm hiểu xem tham số @ListNoteTypeCode XMLcó trống hay không?

Điều gì xảy ra nếu họ gọi thủ tục này như thế này:

declare @p5 int  set @p5=86400 
exec DenormV2.udpProductBulletPointSelectByTier1NoteTypeCode
@Tier1=N'WW099',
@LanguageID=3,
@SeasonItemID=N'16AUT',
@ListNoteTypeCode=N'',
@CacheDuration=@p5 output  select @p5

như đã đề xuất ở đây tôi có thể tránh việc chọn hoàn toàn bằng cách kiểm tra tham số @ListNoteTypeCode.

Mục tiêu chính của tôi trong kịch bản này là lấy dữ liệu với hiệu suất tốt nhất có thể, vì quy trình này không được lưu trong bộ máy chủ web và được gọi hơn một triệu lần mỗi ngày.

Câu trả lời:


7

Bạn có thể kiểm tra NULLvà không có nút ( existphương thức xmlloại):

@ListNoteTypeCode is NULL OR @ListNoteTypeCode.exist('*') = 0

XPath của bạn có thể cụ thể hơn, nếu cần:

@ListNoteTypeCode is NULL OR @ListNoteTypeCode.exist('/BulletPoint/NoteTypeCode/text()') = 0

hình ảnh của bạn. Bạn có thể nói gì không, có phải không? пожалуйста, может объяснить более
Marcello Miorelli

1
@marcellomiorelli Hãy sử dụng tiếng Anh, vì những người khác (những người cũng có thể quan tâm) có thể không hiểu (mặc dù cảm ơn vì tiếng Nga!). Là câu hỏi của bạn về bản thân kiểm tra (nó sẽ giúp thực hiện thủ tục nhanh hơn hay không)? Hay là về '*'vs '/BulletPoint/NoteTypeCode/text()'?
i-một

@marcellomiorelli Bản thân việc kiểm tra có thể giúp thực hiện thủ tục nhanh hơn trong trường hợp, khi xảy ra xmltrường hợp được cung cấp là trống. Trong trường hợp như vậy, SqlServer sẽ không dành tài nguyên cho việc selectbiên dịch câu lệnh tiếp theo (hoặc có thể biên dịch lại) và thực thi, thay vào đó, câu lệnh select "rỗng" có thể được thực thi (đơn giản hơn nhiều) như được đề xuất trong câu hỏi trước.
i-một

1
@marcellomiorelli Về '*'vs '/BulletPoint/NoteTypeCode/text()'. Đây là vấn đề ngữ nghĩa là chủ yếu. Nếu phiên bản đã cho xmlkhông thể chứa các nút khác ngoài chỉ định, thì việc kiểm tra chỉ '*'có thể là đủ. Tuy nhiên, nếu xmlcá thể được cung cấp có thể chứa các nút khác ngoài chỉ định và bạn chỉ sử dụng một phần của thể hiện này xmlthì bạn nên cụ thể hơn trong XPath của mình để kiểm tra xem liệu đã cho xmltrống cho mục đích của Proc được lưu trữ này hay không .
i-một

Tôi sẽ cập nhật câu hỏi ngay khi tôi quản lý để thực hiện và kiểm tra thay đổi này
Marcello Miorelli

3

Một cách khác để kiểm tra tham số, biến hoặc cột XML trống là kiểm tra DATALENGTH. Bất kỳ mục XML trống nào cũng phải là 5 byte. Ví dụ:

DECLARE @Test TABLE (XmlParam XML NULL);
INSERT INTO @Test ([XmlParam]) VALUES (NULL), (N''), (N'g');

SELECT t.[XmlParam],
       DATALENGTH(t.[XmlParam]) AS [DATALENGTH],
       CASE (ISNULL(DATALENGTH(t.[XmlParam]), 5))
          WHEN 5 THEN 'EMPTY'
          ELSE 'Not Empty'
       END AS [IsEmpty]
FROM   @Test t;

Trả về:

XmlParam     DATALENGTH    IsEmpty
--------     ----------    ---------
NULL         NULL          EMPTY
             5             EMPTY
g            9             Not Empty

Xin lưu ý rằng tôi đã sử dụng ISNULL(DATALENGTH(t.[XmlParam]), 5)như vậy sẽ tốt cho việc kiểm tra một tham số hoặc biến. Nếu kiểm tra một cột, nó có thể tốt hơn để sử dụng XmlColumn IS NULL OR DATALENGTH(XmlColumn) = 5.

Cũng xin lưu ý rằng mặc dù có thể thay đổi biểu thị bên trong của dữ liệu XML giữa các phiên bản, tôi đã thử nghiệm trên SQL Server 2008 R2, 2012 và 2014 và kích thước của một mục XML trống luôn là 5.


Tôi tự hỏi nếu điều đó sẽ nhanh hơn (ít tài nguyên người dùng, chu kỳ cpu) hơn @ ListNoteTypeCode.exist ('*') = 0
Marcello Miorelli

1
@marcellomiorelli Cảm giác ruột của tôi là việc kiểm tra DATALENGTHsẽ nhanh hơn việc gọi trình phân tích cú pháp XML, NHƯNG tôi chưa kiểm tra nó. Tuy nhiên, thật dễ dàng để kiểm tra bằng cách tạo tập kết quả gồm 1 triệu hàng (CROSS THAM GIA sys.all_columns) và bao gồm phiên bản của tôi, sau đó xóa phiên bản đó và chạy lại với phiên bản i-one. Xin vui lòng gửi kết quả.
Solomon Rutzky

Làm thế nào bạn phát hiện ra rằng kích thước của một XML trống là 5?
Marcello Miorelli

bạn có thể trả lời nó ở đây
Marcello Miorelli

Tôi đã đăng kết quả so sánh ở đây Xin vui lòng xem khi bạn có cơ hội.
Marcello Miorelli

0

XML của tôi sử dụng Lược đồ. chắc chắn
DATALENGTH sẽ không hoạt động. Ngay cả khi không có Dữ liệu, bạn vẫn sẽ có Schema chiếm một lượng không gian ngẫu nhiên.

Điều này sẽ kiểm tra các phần tử / nút bị thiếu (hoạt động có hoặc không có Schema):

SELECT ISNULL(@ListNoteTypeCode.exist('*:BulletPoint/*:NoteTypeCode'), 0)[HasRows]

Ngoài ra, mục đích của câu hỏi của bạn là cải thiện hiệu suất.
Bạn đang sử dụng một SubQuery tương quan!  : Ôi
! Di chuyển nó vào Biến bảng với bật PK NoteTypeCode.
Sau đó, Tham gia vào Bảng biến của bạn và quên đi tất cả doanh nghiệp Test-For-Missing-Xml này .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.