AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 295787
Accepted
Hannah Vernon
Hannah Vernon
Asked: 2021-07-17 12:38:50 +0800 CST2021-07-17 12:38:50 +0800 CST 2021-07-17 12:38:50 +0800 CST

通过 OPENJSON 优化 json 数据的提取

  • 772

我正在尝试优化从 REST API 获得的值的提取,该 API 在数组中返回 json 值。

这是一个最小的、完整的、可验证的例子,它准确地反映了我正在做的事情。

USE tempdb;

DROP TABLE IF EXISTS dbo.json_test;

CREATE TABLE dbo.json_test
(
    json_test_id                int                 NOT NULL
        IDENTITY(1,1)
    , some_uniqueidentifier     uniqueidentifier    NULL
    , some_varchar              varchar(100)        NULL
    , the_json                  nvarchar(max)       NULL
);

INSERT INTO dbo.json_test (some_uniqueidentifier, some_varchar, the_json)
SELECT 
        some_uniqueidentifier       = NEWID()
      , some_varchar                = CONVERT(varchar(100), CRYPT_GEN_RANDOM(64), 1)
      , the_json = (
            SELECT st.* 
            FROM sys.tables st
                CROSS JOIN sys.tables st2
            WHERE st.object_id = t.object_id FOR JSON AUTO
            )
FROM sys.tables t;

;WITH src AS 
(
    SELECT jt.some_uniqueidentifier
        , jt.some_varchar
        , top_array.[key]
        , top_array.[value]
    FROM dbo.json_test jt
        CROSS APPLY OPENJSON(jt.the_json, N'lax $') top_array
),
src2 AS
(
    SELECT src.some_uniqueidentifier
        , src.some_varchar
        , src.[key]
        , src.[value]
        , inner_key = inner_array.[key]
        , inner_value = inner_array.[value]
    FROM src
        CROSS APPLY OPENJSON(src.[value], N'lax $') inner_array
)
SELECT src2.some_uniqueidentifier
    , src2.some_varchar
    , src2.[key]
    , [name]                                = MAX(CASE WHEN src2.[inner_key] = 'name'                               THEN src2.[inner_value] ELSE NULL END)
    , [object_id]                           = MAX(CASE WHEN src2.[inner_key] = 'object_id'                          THEN src2.[inner_value] ELSE NULL END)
    , [principal_id]                        = MAX(CASE WHEN src2.[inner_key] = 'principal_id'                       THEN src2.[inner_value] ELSE NULL END)
    , [schema_id]                           = MAX(CASE WHEN src2.[inner_key] = 'schema_id'                          THEN src2.[inner_value] ELSE NULL END)
    , [parent_object_id]                    = MAX(CASE WHEN src2.[inner_key] = 'parent_object_id'                   THEN src2.[inner_value] ELSE NULL END)
    , [type]                                = MAX(CASE WHEN src2.[inner_key] = 'type'                               THEN src2.[inner_value] ELSE NULL END)
    , [type_desc]                           = MAX(CASE WHEN src2.[inner_key] = 'type_desc'                          THEN src2.[inner_value] ELSE NULL END)
    , [create_date]                         = MAX(CASE WHEN src2.[inner_key] = 'create_date'                        THEN src2.[inner_value] ELSE NULL END)
    , [modify_date]                         = MAX(CASE WHEN src2.[inner_key] = 'modify_date'                        THEN src2.[inner_value] ELSE NULL END)
    , [is_ms_shipped]                       = MAX(CASE WHEN src2.[inner_key] = 'is_ms_shipped'                      THEN src2.[inner_value] ELSE NULL END)
    , [is_published]                        = MAX(CASE WHEN src2.[inner_key] = 'is_published'                       THEN src2.[inner_value] ELSE NULL END)
    , [is_schema_published]                 = MAX(CASE WHEN src2.[inner_key] = 'is_schema_published'                THEN src2.[inner_value] ELSE NULL END)
    , [lob_data_space_id]                   = MAX(CASE WHEN src2.[inner_key] = 'lob_data_space_id'                  THEN src2.[inner_value] ELSE NULL END)
    , [filestream_data_space_id]            = MAX(CASE WHEN src2.[inner_key] = 'filestream_data_space_id'           THEN src2.[inner_value] ELSE NULL END)
    , [max_column_id_used]                  = MAX(CASE WHEN src2.[inner_key] = 'max_column_id_used'                 THEN src2.[inner_value] ELSE NULL END)
    , [lock_on_bulk_load]                   = MAX(CASE WHEN src2.[inner_key] = 'lock_on_bulk_load'                  THEN src2.[inner_value] ELSE NULL END)
    , [uses_ansi_nulls]                     = MAX(CASE WHEN src2.[inner_key] = 'uses_ansi_nulls'                    THEN src2.[inner_value] ELSE NULL END)
    , [is_replicated]                       = MAX(CASE WHEN src2.[inner_key] = 'is_replicated'                      THEN src2.[inner_value] ELSE NULL END)
    , [has_replication_filter]              = MAX(CASE WHEN src2.[inner_key] = 'has_replication_filter'             THEN src2.[inner_value] ELSE NULL END)
    , [is_merge_published]                  = MAX(CASE WHEN src2.[inner_key] = 'is_merge_published'                 THEN src2.[inner_value] ELSE NULL END)
    , [is_sync_tran_subscribed]             = MAX(CASE WHEN src2.[inner_key] = 'is_sync_tran_subscribed'            THEN src2.[inner_value] ELSE NULL END)
    , [has_unchecked_assembly_data]         = MAX(CASE WHEN src2.[inner_key] = 'has_unchecked_assembly_data'        THEN src2.[inner_value] ELSE NULL END)
    , [text_in_row_limit]                   = MAX(CASE WHEN src2.[inner_key] = 'text_in_row_limit'                  THEN src2.[inner_value] ELSE NULL END)
    , [large_value_types_out_of_row]        = MAX(CASE WHEN src2.[inner_key] = 'large_value_types_out_of_row'       THEN src2.[inner_value] ELSE NULL END)
    , [is_tracked_by_cdc]                   = MAX(CASE WHEN src2.[inner_key] = 'is_tracked_by_cdc'                  THEN src2.[inner_value] ELSE NULL END)
    , [lock_escalation]                     = MAX(CASE WHEN src2.[inner_key] = 'lock_escalation'                    THEN src2.[inner_value] ELSE NULL END)
    , [lock_escalation_desc]                = MAX(CASE WHEN src2.[inner_key] = 'lock_escalation_desc'               THEN src2.[inner_value] ELSE NULL END)
    , [is_filetable]                        = MAX(CASE WHEN src2.[inner_key] = 'is_filetable'                       THEN src2.[inner_value] ELSE NULL END)
    , [is_memory_optimized]                 = MAX(CASE WHEN src2.[inner_key] = 'is_memory_optimized'                THEN src2.[inner_value] ELSE NULL END)
    , [durability]                          = MAX(CASE WHEN src2.[inner_key] = 'durability'                         THEN src2.[inner_value] ELSE NULL END)
    , [durability_desc]                     = MAX(CASE WHEN src2.[inner_key] = 'durability_desc'                    THEN src2.[inner_value] ELSE NULL END)
    , [temporal_type]                       = MAX(CASE WHEN src2.[inner_key] = 'temporal_type'                      THEN src2.[inner_value] ELSE NULL END)
    , [temporal_type_desc]                  = MAX(CASE WHEN src2.[inner_key] = 'temporal_type_desc'                 THEN src2.[inner_value] ELSE NULL END)
    , [history_table_id]                    = MAX(CASE WHEN src2.[inner_key] = 'history_table_id'                   THEN src2.[inner_value] ELSE NULL END)
    , [is_remote_data_archive_enabled]      = MAX(CASE WHEN src2.[inner_key] = 'is_remote_data_archive_enabled'     THEN src2.[inner_value] ELSE NULL END)
    , [is_external]                         = MAX(CASE WHEN src2.[inner_key] = 'is_external'                        THEN src2.[inner_value] ELSE NULL END)
    , [history_retention_period]            = MAX(CASE WHEN src2.[inner_key] = 'history_retention_period'           THEN src2.[inner_value] ELSE NULL END)
    , [history_retention_period_unit]       = MAX(CASE WHEN src2.[inner_key] = 'history_retention_period_unit'      THEN src2.[inner_value] ELSE NULL END)
    , [history_retention_period_unit_desc]  = MAX(CASE WHEN src2.[inner_key] = 'history_retention_period_unit_desc' THEN src2.[inner_value] ELSE NULL END)
    , [is_node]                             = MAX(CASE WHEN src2.[inner_key] = 'is_node'                            THEN src2.[inner_value] ELSE NULL END)
    , [is_edge]                             = MAX(CASE WHEN src2.[inner_key] = 'is_edge'                            THEN src2.[inner_value] ELSE NULL END)
FROM src2
GROUP BY src2.some_uniqueidentifier
    , src2.some_varchar
    , src2.[key]
ORDER BY src2.some_uniqueidentifier
    , src2.some_varchar
    , src2.[key];

无论输入表中包含多少行,查询计划都使用几个嵌套循环连接。想必这是使用CROSS APPLY运算符的神器。为了您的乐趣,我已经设置了一个DB Fiddle。

有没有更有效的方法将数据从 json 格式转换为“真实”的列集?

我使用我的本地 SQL Server 2019 实例创建了上面的代码,但是目标将是 Azure SQL 数据库,因此所有最新和最好的选项都可用。

sql-server azure-sql-database
  • 2 2 个回答
  • 991 Views

2 个回答

  • Voted
  1. Best Answer
    Biju jose
    2021-07-17T23:19:35+08:002021-07-17T23:19:35+08:00

    WITH您应该使用该子句直接从 json 数组中提取值,如下所示:

    SELECT src.*
        , tt.*
    FROM json_test src
    CROSS APPLY OPENJSON(src.the_json , 'lax $')
        WITH (
              [name]                               sysname       '$.name'
            , [object_id]                          int           '$.object_id'
            , [principal_id]                       int           '$.principal_id'
            , [schema_id]                          smallint      '$.schema_id'
            , [parent_object_id]                   int           '$.parent_object_id'
            , [type]                               char(2)       '$.type'
            , [type_desc]                          nvarchar(60)  '$.type_desc'
            , [create_date]                        datetime      '$.create_date'
            , [modify_date]                        datetime      '$.modify_date'
            , [is_ms_shipped]                      bit           '$.is_ms_shipped'
            , [is_published]                       bit           '$.is_published'
            , [is_schema_published]                bit           '$.is_schema_published'
            , [lob_data_space_id]                  int           '$.lob_data_space_id'
            , [filestream_data_space_id]           int           '$.filestream_data_space_id'
            , [max_column_id_used]                 int           '$.max_column_id_used'
            , [lock_on_bulk_load]                  bit           '$.lock_on_bulk_load'
            , [uses_ansi_nulls]                    bit           '$.uses_ansi_nulls'
            , [is_replicated]                      bit           '$.is_replicated'
            , [has_replication_filter]             bit           '$.has_replication_filter'
            , [is_merge_published]                 bit           '$.is_merge_published'
            , [is_sync_tran_subscribed]            bit           '$.is_sync_tran_subscribed'
            , [has_unchecked_assembly_data]        bit           '$.has_unchecked_assembly_data'
            , [text_in_row_limit]                  int           '$.text_in_row_limit'
            , [large_value_types_out_of_row]       bit           '$.large_value_types_out_of_row'
            , [is_tracked_by_cdc]                  bit           '$.is_tracked_by_cdc'
            , [lock_escalation]                    tinyint       '$.lock_escalation'
            , [lock_escalation_desc]               nvarchar(60)  '$.lock_escalation_desc'
            , [is_filetable]                       bit           '$.is_filetable'
            , [is_memory_optimized]                bit           '$.is_memory_optimized'
            , [durability]                         tinyint       '$.durability'
            , [durability_desc]                    nvarchar(60)  '$.durability_desc'
            , [temporal_type]                      tinyint       '$.temporal_type'
            , [temporal_type_desc]                 nvarchar(60)  '$.temporal_type_desc'
            , [history_table_id]                   int           '$.history_table_id'
            , [is_remote_data_archive_enabled]     bit           '$.is_remote_data_archive_enabled'
            , [is_external]                        bit           '$.is_external'
            , [history_retention_period]           int           '$.history_retention_period'
            , [history_retention_period_unit]      int           '$.history_retention_period_unit'
            , [history_retention_period_unit_desc] nvarchar(10)  '$.history_retention_period_unit_desc'
            , [is_node]                            bit           '$.is_node'
            , [is_edge]                            bit           '$.is_edge'
        ) AS tt
    

    这个 Fiddle比较了两种方法的输出,证明结果是相同的。

    输出中唯一缺少的列是表值函数key生成的值,该OPENJSON值仅在未WITH指定子句时返回。我的变体计划只有一个嵌套循环,而且似乎效率更高。

    在此处输入图像描述

    OPENJSON CROSS APPLY 的 Microsoft Docs 示例

    • 7
  2. D-K
    2021-09-25T08:33:23+08:002021-09-25T08:33:23+08:00

    我最近遇到了这个问题,这是一种以类似索引的速度加快对 json 的访问的方法:

    https://bertwagner.com/posts/one-sql-cheat-code-for-amazingly-fast-json-queries/

    不确定这是否允许,但我将在此处复制并粘贴一些博客:

    最近我一直在 SQL Server 2016 中使用 JSON 很多。

    许多人对在 SQL Server 中使用 JSON 的犹豫之一是他们认为查询它一定很慢——SQL 应该擅长关系数据,而不是字符串解析,对吧?

    事实证明,独立 SQL Server JSON 函数的性能非常好。更好的是,通过在 JSON 解析的计算列上使用索引,可以以惊人的速度对 JSON 数据进行查询。在这篇文章中,我想看看 SQL 如何能够以如此出色的性能解析*。

    *这里的“解析”实际上是一个谎言——它在幕后做着别的事情。你会明白我的意思,继续阅读!

    • 1

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve