Как заменить курсор SQL Server другим механизмом - PullRequest
0 голосов
/ 17 апреля 2019

Я работаю над SQL Server 2008. Мне нужно создать json из двух таблиц, которые имеют отношение один ко многим. Таблицы Customer и Orders.

У каждого клиента может быть один или несколько заказов. Json создается путем получения данных из таблицы клиентов, а затем добавления всех покупок, которые они совершили.

Ниже мой запрос. Я также приложил вывод json из запроса. Это работает и создает действительные jsons. Проблема в том, что это слишком медленно, так как я использую курсор для циклического перемещения по таблице Customer. Мне удалось избежать курсора, чтобы получить данные из таблицы Orders, используя для пути XML. Поскольку мне приходится обрабатывать миллионы строк, я должен заменить курсор каким-либо другим механизмом.

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

enter image description here

1 Ответ

2 голосов
/ 17 апреля 2019

Я не могу проверить это, но я подозреваю, что вы могли бы переписать вышеприведенное как метод, основанный на множестве, как показано ниже (так как у меня нет способа проверить это, я не могу быть уверен, что это сработаетесли это не так, вам может потребоваться немного устранить ее) :

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

Учитывая, что OP имеет 5 миллионов строк, тогда это, вероятно, будет много для одного пакета.Разделение его на порцию, скажем, 10000 может быть лучше для производительности по всем.К сожалению, OP по-прежнему использует 2008, поэтому у них нет доступа к предложению OFFSET.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...