Избегайте использования нескольких операторов INSERT при вставке данных из JSON в таблицу базы данных - PullRequest
0 голосов
/ 05 августа 2020

Я написал хранимую процедуру на SQL сервере, которая принимает в качестве входных данных следующее JSON сообщение:

{"sentiment_results": {"polarity": -0.6, "subjectivity": 0.7, "emotions": {"anger": 0.08296050131320953, "disgust": 0.00219865539111197, "fear": 0.07708118110895157, "joy": 0.757244884967804, "surprise": 0.027166856452822685, "sadness": 0.05334791541099548}}, "sentiment_time": "2020-08-04T16:43:47.141948"}

... и использует следующий сценарий для ввода данных на таблица базы данных (таблица post_metric_score -> одна строка для каждой точки данных)

         INSERT INTO [STAGING].[post_metric_score]([post_id],[metric_id],[score])
            SELECT @post_id, 1, try_convert(decimal(12, 8), [score])
            FROM OPENJSON(@postJson, '$.sentiment_results')
                WITH ([score] FLOAT '$.polarity')

            INSERT INTO [STAGING].[post_metric_score]([post_id],[metric_id],[score])
            SELECT @post_id, 2, try_convert(decimal(12, 8), [score])
            FROM OPENJSON(@postJson, '$.sentiment_results')
                WITH ([score] FLOAT '$.subjectivity')

            INSERT INTO [STAGING].[post_metric_score]([post_id],[metric_id],[score])
            SELECT @post_id, 3, try_convert(decimal(12, 8), [score])
            FROM OPENJSON(@postJson, '$.sentiment_results.emotions')
                WITH ([score] FLOAT '$.anger')

            INSERT INTO [STAGING].[post_metric_score]([post_id],[metric_id],[score])
            SELECT @post_id, 4, try_convert(decimal(12, 8), [score])
            FROM OPENJSON(@postJson, '$.sentiment_results.emotions')
                WITH ([score] FLOAT '$.disgust')

            INSERT INTO [STAGING].[post_metric_score]([post_id],[metric_id],[score])
            SELECT @post_id, 5, try_convert(decimal(12, 8), [score])
            FROM OPENJSON(@postJson, '$.sentiment_results.emotions')
                WITH ([score] FLOAT '$.fear')

            INSERT INTO [STAGING].[post_metric_score]([post_id],[metric_id],[score])
            SELECT @post_id, 6, try_convert(decimal(12, 8), [score])
            FROM OPENJSON(@postJson, '$.sentiment_results.emotions')
                WITH ([score] FLOAT '$.joy')

Скрипт работает нормально, но использует много ресурсов ЦП, поскольку выполняет один и тот же запрос вставки 6 раз на JSON сообщение.

Есть ли способ упростить приведенный выше сценарий, чтобы не выполнять оператор вставки несколько раз?

Ответы [ 2 ]

1 голос
/ 05 августа 2020

Другой вариант - использовать JSON_VALUE() (обратите внимание, что OPENJSON(), вероятно, быстрее, чем использование JSON_VALUE() шесть раз):

INSERT INTO [STAGING].[post_metric_score]([post_id], [metric_id], [score])
SELECT @postId, [metric_id], TRY_CONVERT(decimal(12, 8), [score])
FROM (VALUES 
    (1, JSON_VALUE(@postJson, '$.sentiment_results.polarity')),
    (2, JSON_VALUE(@postJson, '$.sentiment_results.subjectivity')),
    (3, JSON_VALUE(@postJson, '$.sentiment_results.emotions.anger')),
    (4, JSON_VALUE(@postJson, '$.sentiment_results.emotions.disgust')),
    (5, JSON_VALUE(@postJson, '$.sentiment_results.emotions.fear')),
    (6, JSON_VALUE(@postJson, '$.sentiment_results.emotions.joy'))
) v ([metric_id], [score]) 
1 голос
/ 05 августа 2020

Вы можете открыть JSON один раз, получить нужные столбцы и развернуть, используя apply. Вот пример с двумя столбцами:

INSERT INTO [STAGING].[post_metric_score]([post_id], [metric_id], [score])
    SELECT @post_id, v.metric_id, try_convert(decimal(12, 8), v.score)
    FROM OPENJSON(@postJson, '$.sentiment_results')
         WITH (polarity FLOAT '$.polarity',
               subjectivity FLOAT '$.subjectivity'
              ) as o CROSS APPLY
         (VALUES (1, o.polarity), (2, o.subjectivity)
         ) v(metric_id, score);

Со всеми столбцами:

INSERT INTO [STAGING].[post_metric_score]([post_id], [metric_id], [score])
    SELECT @post_id, v.metric_id, try_convert(decimal(12, 8), v.score)
    FROM OPENJSON(@postJson, '$.sentiment_results')
         WITH (polarity FLOAT '$.polarity',
               subjectivity FLOAT '$.subjectivity',
               anger FLOAT '$.emotions.anger',
               disgust FLOAT '$.emotions.disgust',
               fear FLOAT '$.emotions.fear',
               joy FLOAT'$.emotions.joy'
              ) as o CROSS APPLY
         (VALUES (1, o.polarity), (2, o.subjectivity), (3, o.anger), (4, o.disgust), (5, o.fear), (6, o.joy)
         ) v(metric_id, score);

Здесь - это SQL скрипка.

...