Json 如何用不同的机制替换SQL Server游标

Json 如何用不同的机制替换SQL Server游标,json,sql-server,Json,Sql Server,我正在使用SQLServer2008。我必须从两个具有一对多关系的表中创建json。这些表是客户和订单 每个客户可能有一个或多个订单。json的构造方法是首先从customer表中获取数据,然后附加他们所购买的所有商品 以下是我的疑问。我还附上了查询的json输出。它工作并创建有效的JSON。问题是它太慢了,因为我使用光标在Customer表中循环。通过使用for xml path,我成功地避免了游标从Orders表中获取数据。因为我必须处理数百万行,所以我必须用其他机制替换光标 DECLARE

我正在使用SQLServer2008。我必须从两个具有一对多关系的表中创建json。这些表是
客户
订单

每个客户可能有一个或多个订单。json的构造方法是首先从customer表中获取数据,然后附加他们所购买的所有商品

以下是我的疑问。我还附上了查询的json输出。它工作并创建有效的JSON。问题是它太慢了,因为我使用光标在
Customer
表中循环。通过使用for xml path,我成功地避免了游标从
Orders
表中获取数据。因为我必须处理数百万行,所以我必须用其他机制替换光标

DECLARE @PaymentType VARCHAR(50),
        @Email VARCHAR(100), 
        @OrderId INT

DECLARE CustomerCursor CURSOR FAST_FORWARD FOR
    SELECT TOP 10 
        PaymentType, Email, OrderId 
    FROM 
        CUSTOMER

OPEN CustomerCursor

FETCH NEXT FROM CustomerCursor INTO @PaymentType, @Email, @OrderId

WHILE (@@FETCH_STATUS = 0)
BEGIN
    DECLARE @customer VARCHAR(MAX)
    DECLARE @order VARCHAR(MAX)
    DECLARE @customer_with_order VARCHAR(MAX)

    -- construct order json
    SET @order =  '[' + STUFF((SELECT ',{"orderProductID":' + CAST(orderProductID AS VARCHAR) + 
                                      ',"productType":"' + ProductType + '"' + 
                                      ',"productName":"' + ProductName + '"' +
                                      ',"categoryName":"' + CategoryName + '"' + '}'
                               FROM ORDERS 
                               WHERE orderid = @OrderId
                               FOR XML PAT(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 1, '') + ']'
    -- construct customer json
    SET @customer = '{"email":"' + CASE WHEN @Email IS NULL THEN '' ELSE 
   @Email END + '"'
                + ',"eventName": "ChristmasSale", "dataFields": {' 
                + '"orderId":' + CAST(CASE WHEN @OrderId IS NULL THEN 0 ELSE 
    @OrderId  END AS VARCHAR)                   
                + ',"paymentType":"' + CASE WHEN @PaymentType IS NULL THEN 
    '' ELSE @PaymentType END + '"'                  
                + ',"products": '

    -- combine these two
    SET @customer_with_order = @customer + @order + '}}'

    -- insert into CUSTOMER_ORDER_DATA
    INSERT INTO CUSTOMER_ORDER_DATA(email, order_id, orders) 
    VALUES (@Email, @OrderId, @customer_with_order)

    FETCH NEXT FROM CustomerCursor INTO @PaymentType, @Email, @OrderId
END

CLOSE CustomerCursor
DEALLOCATE CustomerCursor

我无法测试这一点,但我怀疑您可以将上述内容重写为基于集合的方法,如下所示(因为我无法测试这一点,我无法确定这是否可行,如果不行,您可能需要对其进行一点故障排除):


考虑到OP有500万行,那么对于一个批次来说这可能有点多。将其分为批量(比如10000)可能对整体性能更好。不幸的是,OP仍在使用2008,因此他们无法访问
OFFSET
子句。

我无法测试这一点,但我怀疑您可以将上述内容重写为基于集合的方法,如下所示(因为我无法测试这一点,我无法确定这是否可行,如果不行,您可能需要对其进行一点故障排除):


考虑到OP有500万行,那么对于一个批次来说这可能有点多。将其分为批量(比如10000)可能对整体性能更好。不幸的是,OP仍在使用2008,因此他们无法访问
OFFSET
子句。

define slow-here——您预计生成100万个json文件需要多快?可能是你的存储速度不够快。我必须处理500万条记录。对于1000个JSON,上述查询耗时5分钟。按照这个速度,需要400小时!将值保留为关系数据并在SQL Server之外创建JSON不是更快吗?嗨,Luis,我在C#中尝试过,它也需要类似的时间,因为它还涉及到循环记录。我不是说一次转换所有内容,只是根据需要转换为JSON。您还向存储中添加了不必要的数据,这最终会给您带来不好的影响。存储的每一行都有超过200字节的冗余数据。所有这些看起来都是糟糕的设计。在这里定义慢——您希望以多快的速度生成100万个json文件?可能是你的存储速度不够快。我必须处理500万条记录。对于1000个JSON,上述查询耗时5分钟。按照这个速度,需要400小时!将值保留为关系数据并在SQL Server之外创建JSON不是更快吗?嗨,Luis,我在C#中尝试过,它也需要类似的时间,因为它还涉及到循环记录。我不是说一次转换所有内容,只是根据需要转换为JSON。您还向存储中添加了不必要的数据,这最终会给您带来不好的影响。存储的每一行都有超过200字节的冗余数据。所有这些看起来都是糟糕的设计。嗨,Larnu,经过一些小的修改,它工作得非常完美。这比使用光标的方法至少快600%。非常感谢。嗨,Larnu,经过一些小的修改,它工作得非常好。这比使用光标的方法至少快600%。非常感谢。
INSERT INTO CUSTOMER_ORDER_DATA(email, order_id, orders)
SELECT C.Email,
       C.orderid,
       '{"email":"' + CASE WHEN @Email IS NULL THEN '' ELSE 
   @Email END + '"'
                + ',"eventName": "ChristmasSale", "dataFields": {' 
                + '"orderId":' + CAST(CASE WHEN @OrderId IS NULL THEN 0 ELSE 
    @OrderId  END AS varchar)                   
                + ',"paymentType":"' + CASE WHEN @PaymentType IS NULL THEN 
    '' ELSE @PaymentType END + '"'                  
                + ',"products": ' +
    ('[' + STUFF((
    SELECT 
        ',{"orderProductID":' + CAST(orderProductID AS varchar)
        + ',"productType":"' + ProductType + '"'
        + ',"productName":"' + ProductName + '"'
        + ',"categoryName":"' + CategoryName + '"'          
        +'}'
    FROM ORDERS AS O
    WHERE O.orderid = C.orderid
    FOR XML PATH(''),TYPE).value('.', 'varchar(max)'), 1, 1, '') + ']')
FROM CUSTOMER AS C