Когда я могу сохранить JSON или XML-данных в таблицу SQL

При использовании SQL или MySQL в (или любой реляционной БД на то пошло) - я понимаю, что сохранение данных в регулярные колонки лучше ради индексации и других целей...

Дело в том загрузки и сохранения JSON с данных иногда гораздо более простой. и упрощает разработку.

Есть ли какие-то "золотого правила" и для экономии сырья JSON с данных в БД?

это абсолютно неправильная практика, чтобы сделать так?

Резюме

Очень хорошие ответы были даны, но, несомненно, наиболее хорошо организованный ответ дал @Shnugo, которое заслуживает награды.

Также хотелось бы отметить ответы @Гордон Linoff и @Amresh Пандей для объяснения других специальных случаев использования.

Слава Богу, и хорошую работу всем!

Комментарии к вопросу (1)
Решение

Основные вопросы

  • Что вы собираетесь делать с этими данными? и
  • Как вы фильтрации/сортировки/присоединения/манипулирующие этими данными? JSON-формате (например, XML) отлично подходит для обмена данными, хранения мелких и генетически определенных структур, но он не может участвовать в типичные действия вы работать в вашей РСУБД. В большинстве случаев это будет лучше для передачи данных JSON в нормальных таблицах и повторно создать объект JSON, когда вам это нужно.

    В XML / JSON и 1.НФ

    Первое правило диктует нормализации, никогда не хранить больше одного бита информации в одну колонку. Вы видите колонку "в PersonName" с значение, как-то "Микки Маус" и? Вам указывают на это и плакать: изменить это немедленно! Насчет XML или JSON? Эти типы разрыва 1.НФ? Ну да и нет...&ампер;усилитель; nbsp; Это совершенно нормально, чтобы сохранить полную структуру как один бит информации если один бит информации на самом деле. Вы получаете мыло ответ и хотите сохранить его, потому что тебе это пригодится в будущем (а вы не использовать эти данные для собственных процессов)? Просто магазин это как! А теперь представьте сложную структуру (XML или JSON), представляющие человека (с его адреса, дополнительная информация...). Теперь вы кладете этот в один столбец, как PersonInCharge. Разве это неправильно? Должны'т жить в правильно спроектированной связанных таблиц с внешним ключом ссылку, а не в XML или JSON? Особенно если один и тот же человек может произойти во многих различных строк, это, безусловно, неправильно использовать подход с XML/JSON-файле. А теперь представьте себе, как нужно хранить исторические данные. Вы хотите сохраняться человек's данные на данный момент времени. Несколько дней спустя человек говорит вам новый адрес? Нет проблем! По старому адресу живет в XML/JSON если вы когда-нибудь понадобится... Вывод: Если вы храните данные просто держать его, это'ы в порядке. Если эти данные-это уникальный часть, это'ы хорошо... Но если вам нужны внутренние части регулярно или если это будет означать, дублирующие хранения это's не хорошо...

    Физического хранилища

    Следующее для SQL Server и могут отличаться в других РСУБД. XML не сохраняется как текст, который вы видите, а как иерархическое дерево. Запрос это удивительно хорошо! Эта структура не анализируется на уровне строки! JSON в SQL-сервер (2016+) живет в строке и должен быть проанализирован. Нет реального родной типа JSON (как есть родной типа XML). Это может прийти позже, но сейчас я'd и предположим, что JSON будет не таким производительным, как XML на SQL Server (см. раздел Обновление 2). Какие нужно прочитать значение из JSON будет нужно чертовски много скрытых строку вызова метода...

Что это значит для вас?

твой милый художник ДБ :-D не знает, что хранение в JSON как является, против общих принципов РСУБД. Он знает,

  • что JSON-это вполне возможно нарушая 1.НФ

  • что формат JSON может меняться во времени (те же колонны, различные материалы).

  • что JSON-это не просто читать, а это очень тяжело для фильтрации/поиска/присоединиться или отсортировать по нему.

  • что такие операции сместится совсем немного дополнительную нагрузку на бедный сервер БД Есть некоторые обходные пути (в зависимости от СУБД, которую вы используете), но большинство из них не'т работать так, как вы'd, как это...

    Ответ на ваш вопрос короче

    Да

  • Если вы не хотите использовать данные, которые хранятся в свой формат JSON для дорогостоящих операций (фильтр/объединение/сортировка). Вы можете хранить это как и любой другой существует только содержание. Мы храним много картинок в BLOB, но мы бы не попробовать, чтобы отфильтровать все изображения с цветком...

  • Если вас не беспокоит то, что's внутри (просто хранить и читать его как один бит информации)

  • Если структуры переменной, что затруднит для создания физических таблиц для работы с данными в формате JSON.

  • Если структура вложенности, что хранение в физических таблицах на большие расходы Нет

  • Если вы хотите использовать внутренние данные, такие как вы'd с помощью реляционной таблицы'данных (фильтр, индексов, соединений...)

  • Если вы будете хранить дубликаты (создать избыточность)

  • В общем: если вы сталкиваетесь с проблемами производительности (наверняка, вы будете сталкиваться с ними во многих типичных сценариях!) Вы можете начать с JSON в столбец, строку или как Blob и изменить это физические таблицы, когда вам это нужно. Мой волшебный хрустальный шар говорит мне, это может быть завтра :-Д

    Обновление

    Найти некоторые идеи о производительности и дискового пространства здесь: https://stackoverflow.com/a/47408528/5089204

    Обновление 2: подробнее о производительности...

    По следующим адресам JSON и XML в SQL-серверу 2016 Пользователь @mike123 указал на статьи о официальный Microsoft blog, который, кажется, подтверждение в эксперименте, что запрос и JSON 10 х быстрее затем запросе XML в SQL-сервере. Некоторые мысли о том, что: Некоторые кросс-проверки на "Эксперимент" и:

  • в то"Эксперимент" и мер много, но не представление об XML и формат JSON. Делаем те же действия с той же (неизменной) строку несколько раз-это не реалистичный сценарий

  • Протестированные примеры далеко просто для общего заявления!

  • Чтение значения всегда одинаковы и даже не используется. Оптимизатор будет видеть это...

  • Ни одного слова о поддержке могучий язык XQuery! Найти продукт с заданным ID в массив? Формат JSON должен прочитать много и применить фильтр, используягде, ав формате XML позволит внутренним XQuery и предиката. Не говоря оflwor покажется`...

  • в "экспериментов" и код, как на моей системе воспитывает: в JSON, кажется, 3 раза быстрее (но не в 10 раз).

  • Добавление /текст() К в XPath уменьшает это меньше, чем 2 раза. В статье, касающейся пользователей и"Мистер Магу" и указал на это уже, но нажмите кнопку-приманка название остается неизменным...

  • С такой простой JSON, так как приведенный в "Эксперимент" и самый быстрый чистый Т-SQL для подхода было сочетание подстрока и функция charindex :-Д Следующий код покажет более реалистичный эксперимент

  • Использование JSON и идентичный XML с более чем одного "продукта" (в формате JSON массив и одноуровневых узлов)

  • JSON и XML изменяются незначительно (10000 побегушках) и вставлять в таблицы.

  • Есть первоначальный вызов с обоих таблицах, чтобы избежать первый звонок-смещение

  • Все 10000 записей будут читать и значениями, полученными вставляются в другую таблицу.

  • Используя на 10 пройдет через этот блок в десять раз, чтобы избежать первый звонок-смещение Конечный результат наглядно показывает, что JSON-это медленнее, чем XML (не так много, около 1,5 х по-прежнему очень простой пример). Заключительное заявление:

  • С чрезмерно упрощенный пример при неоправданных обстоятельствах JSON может быть быстрее, чем XML

  • Работа с JSON-это чисто строка действия, в то время как XML разбирается и трансформируется. Это довольно дорого в первом действии, но ускорит все, как только это будет сделано.

  • Формат JSON может быть лучше в один раз акция (позволяет избежать накладных расходов на создание внутренней иерархическое представление XML)

  • С еще очень простой, но более реалистичный пример XML будет быстрее в простое чтение

  • Всякий раз, когда возникает необходимость прочитать конкретный элемент из массива, чтобы отфильтровать все записи, где указанного productid входит в массив, или для перемещения вверх и вниз по тропинке, в JSON не выдерживают. Она должна быть разобрана строки полностью - каждый раз, когда вы должны захватить в него... Тестовый код

USE master;
GO
--create a clean database
CREATE DATABASE TestJsonXml;
GO
USE TestJsonXml;
GO
--create tables
CREATE TABLE TestTbl1(ID INT IDENTITY,SomeXml XML);
CREATE TABLE TestTbl2(ID INT IDENTITY,SomeJson NVARCHAR(MAX));
CREATE TABLE Target1(SomeString NVARCHAR(MAX));
CREATE TABLE Target2(SomeString NVARCHAR(MAX));
CREATE TABLE Times(Test VARCHAR(10),Diff INT)
GO
--insert 10000 XMLs into TestTbl1
WITH Tally AS(SELECT TOP 10000 ROW_NUMBER() OVER(ORDER BY (SELECT NULL))*2 AS Nmbr FROM master..spt_values AS v1 CROSS APPLY master..spt_values AS v2)
INSERT INTO TestTbl1(SomeXml)
SELECT 
N'



            ' + CAST(Nmbr AS NVARCHAR(10)) + ' year parts and labor extended maintenance is available
            1 year parts and labor

        ' + CAST(Nmbr AS NVARCHAR(10)) + '
        Road Bike



            ' + CAST(Nmbr + 1 AS NVARCHAR(10)) + ' blah
            1 year parts and labor

        ' + CAST(Nmbr + 1 AS NVARCHAR(10)) + '
        Cross Bike


'
FROM Tally;

--insert 10000 JSONs into TestTbl2
WITH Tally AS(SELECT TOP 10000 ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS Nmbr FROM master..spt_values AS v1 CROSS APPLY master..spt_values AS v2)
INSERT INTO TestTbl2(SomeJson)
SELECT 
N'{
    "Root": {
        "Products": {
            "ProductDescription": [
                {
                    "Features": {
                        "Maintenance": "' + CAST(Nmbr AS NVARCHAR(10)) + ' year parts and labor extended maintenance is available",
                        "Warranty": "1 year parts and labor"
                    },
                    "ProductID": "' + CAST(Nmbr AS NVARCHAR(10)) + '",
                    "ProductName": "Road Bike"
                },
                {
                    "Features": {
                        "Maintenance": "' + CAST(Nmbr + 1 AS NVARCHAR(10)) + ' blah",
                        "Warranty": "1 year parts and labor"
                    },
                    "ProductID": "' + CAST(Nmbr + 1 AS NVARCHAR(10)) + '",
                    "ProductName": "Cross Bike"
                }
            ]
        }
    }
}'
FROM Tally;
GO

--Do some initial action to avoid first-call-bias
INSERT INTO Target1(SomeString)
SELECT SomeXml.value('(/Root/Products/ProductDescription/Features/Maintenance/text())[1]', 'nvarchar(4000)')
FROM TestTbl1;
INSERT INTO Target2(SomeString)
SELECT JSON_VALUE(SomeJson, N'$.Root.Products.ProductDescription[0].Features.Maintenance')
FROM TestTbl2;
GO

--Start the test
DECLARE @StartDt DATETIME2(7), @EndXml DATETIME2(7), @EndJson DATETIME2(7);

--Read all ProductNames of the second product and insert them to Target1
SET @StartDt = SYSDATETIME();
INSERT INTO Target1(SomeString)
SELECT SomeXml.value('(/Root/Products/ProductDescription/ProductName/text())[2]', 'nvarchar(4000)')
FROM TestTbl1
ORDER BY NEWID();
--remember the time spent
INSERT INTO Times(Test,Diff)
SELECT 'xml',DATEDIFF(millisecond,@StartDt,SYSDATETIME());

--Same with JSON into Target2
SET @StartDt = SYSDATETIME();
INSERT INTO Target2(SomeString)
SELECT JSON_VALUE(SomeJson, N'$.Root.Products.ProductDescription[1].ProductName')
FROM TestTbl2
ORDER BY NEWID();
--remember the time spent
INSERT INTO Times(Test,Diff)
SELECT 'json',DATEDIFF(millisecond,@StartDt,SYSDATETIME());

GO 10 --do the block above 10 times

--Show the result
SELECT Test,SUM(Diff) AS SumTime, COUNT(Diff) AS CountTime
FROM Times
GROUP BY Test;
GO
--clean up
USE master;
GO
DROP DATABASE TestJsonXml;
GO

Результат (в SQL Server 2016 и оставьте на Асер Aspire В17 Нитро процессор i7, 8ГБ ОЗУ)

Test    SumTime 
------------------
json    2706    
xml     1604    
Комментарии (6)

Это слишком долго для комментария.

Если бы это было "и абсолютно неправильно" и большинство баз данных не поддерживает. Ладно, большинство баз данных поддерживают запятые в " с " п. и я считаю, что как "совершенно неверно то". Но поддержка JSON-это новая разработка, не совместима с "функция" по.

Один очевидный случай, когда в JSON struct-это просто объект, который передается обратно в приложение. Тогда нет дискуссии -- других тогда накладные расходы на хранение JSON, который является излишне подробны для структурированных данных с помощью общих полей в каждой записи.

Другое дело, что "редкая" в случае колонны. У вас есть строки со многими возможными столбцами, но это меняется от строки к строке.

Другое дело, когда вы хотите сохранить как "вложенные" по записи в запись. JSON-это мощный.

Если в JSON имеет общие поля в записи, которые вы хотите запросить, то, как правило, лучше положить их в надлежащие столбцы базы данных. Однако, данные сложные и есть место для форматы, такие как JSON.

Комментарии (0)

Я'МР волна моя волшебная палочка. Пуф! Золотые правила на использование JSON:

  • Если MySQL не нужно искать inside в JSON, а приложение просто набор всякой всячины, затем JSON-это хорошо, возможно даже лучше.

  • Если вы ищете на данных, внутри и вы MariaDB в 10.0.1 или MySQL 5.7 (с типом данных JSON и функции), затем в JSON might быть практичным. С помощью "динамический&quot Как версию MariaDB 5.3' столбцы-это вариант.

  • Если вы делаете назальный сущность-атрибут-значение; вещи, затем JSON-это не хорошо, но это меньшее из нескольких зол. http://mysql.rjweb.org/doc.php/eav

  • Поиск по индексированному столбцу, не имея значения похоронен внутри JSON-это большой плюс.

  • Для поиска по диапазону на индексированный столбец, или полнотекстового поиска или пространственные, JSON-это не возможно.

  • К где A=1 и B=2 в "композит" по-показатель индекса(а,б)` большая, вероятно, может'т близко с JSON.

  • В JSON хорошо работает с "редкая" в данных; индексация работает, но не так хорошо, с такой. (Я имею в виду ценности, которые 'Нет' или null для многих строк.)

  • JSON может дать тебя "блоки" и "деревья" без обращения к дополнительной таблиц(ы). Но копаться в таких массивов/деревья только в приложение, не в SQL.

  • JSON-это миры лучше, чем XML. (Мое мнение)

  • Если вы не хотите попасть в строку JSON исключением из приложения, то я рекомендую изменение размера (на стороне клиента), его хранение в клякса. Думайте о нем, как .в JPG-там'ы там всякие, но SQL не волнует.

Состояние вашего приложения; может быть, мы можем быть более конкретными.

Комментарии (7)

Новый SQL Server предлагает функции для обработки текста JSON. Данные в формате JSON можно хранить как текст в стандартных столбцов SQL Server и SQL Server обеспечивает функции, которые могут вернуть ценности этих объектов JSON.

    DROP TABLE IF EXISTS Person

 CREATE TABLE Person 
 ( _id int identity constraint PK_JSON_ID primary key,
 value nvarchar(max)
 CONSTRAINT [Content should be formatted as JSON]
 CHECK ( ISJSON(value)>0 )
 )

Эта простая конструкция аналогична стандартной СУБД коллекции, которые вы можете создать в базах данных NoSQL (например, Azure DocumentDB или в MongoDB), где вы просто есть ключ, который представляет собой идентификатор и значение, которое представляет в JSON.

Обратите внимание, что тип nvarchar-это не просто обычный текст. В SQL Server имеет встроенный механизм сжатия текста, которые могут прозрачно сжимать данные, хранящиеся на диске. Сжатия зависит от языка и может доходить до 50% в зависимости от ваших данных (см. сжатие Юникод ).

Ключевая разница между SQL Server и других простой NoSQL баз данных является то, что SQL Server позволяет использовать гибридную модель данных, где можно хранить несколько объектов JSON в той же “коллекции”, и объединить их с регулярными реляционных столбцов.

В качестве примера, представьте, что мы знаем, что каждый человек в вашей коллекции будет иметь firstName и lastName, и что вы можете хранить общую информацию о человеке, как один объект JSON, а также номера телефонов/адреса электронной почты в качестве отдельных объектов. В SQL Server 2016 и мы можем легко создать эту структуру без какого-либо дополнительного синтаксиса:

DROP TABLE IF EXISTS Person

CREATE TABLE Person (

 PersonID int IDENTITY PRIMARY KEY,

 FirstName nvarchar(100) NOT NULL,

 LastName nvarchar(100) NOT NULL,

 AdditionalInfo nvarchar(max) NULL,

 PhoneNumbers nvarchar(max) NULL,

 EmailAddresses nvarchar(max) NULL
 CONSTRAINT [Email addresses must be formatted as JSON array]
 CHECK ( ISJSON(EmailAddresses)>0 )

 )

Вместо того, чтобы один объект JSON, вы можете организовать ваши данные в этой “коллекции”. Если вы не хотите, чтобы явно проверить структуру каждого столбца в JSON, вам не нужно добавить в JSON проверить ограничение на каждый столбец (в данном примере я добавил чек ограничение только на колонки EmailAddresses).

Если сравнить эту структуру в стандартной коллекции в NoSQL, вы можете заметить, что вы будете иметь быстрый доступ к строго типизированные данные (firstName и lastName). Поэтому такое решение является хорошим выбором для гибридных моделей, где вы можете найти некоторые сведения, которые повторяются по всем объектам, и другая переменная информация может храниться в виде JSON. Таким образом, вы можете совместить гибкость и производительность.

Если сравнить эту структуру со схемой таблицы базы данных AdventureWorks человека, можно заметить, что у нас выведено множество связанных таблиц.

Кроме простоты схемы, операции доступа к данным будет проще по сравнению со сложной структурой. Сейчас вы можете читать одну таблицу, вместо того чтобы объединить несколько таблиц. Когда нужно вставить новое лицо с соответствующей информацией (адреса, телефоны) вы можете вставить одну запись в одной таблице, а не вставка одной записи в базе данных AdventureWorks человека, стола, принимая столбец идентификаторов, чтобы найти внешний ключ, который будет использоваться для хранения телефонов, адресов электронной почты и т. д. Кроме того, в этой модели можно легко удалить одиночный рядок человек без каскадное удаление с помощью внешнего ключа отношения.

NoSQL баз данных оптимизированы для простого, чтение, добавление и удаление операций – сервер SQL 2016 позволяет применить ту же логику в реляционной базе данных.

Ограничения в JSON В предыдущих примерах мы видели, как добавить простое ограничение, которое проверяет, что текст хранится в столбце правильно отформатирован. Хотя в JSON не имеют сильной схемы, также можно добавить сложные трудности, объединив функции, которые считывают значения из JSON и стандарт T-SQL функций:

ALTER TABLE Person
 ADD CONSTRAINT [Age should be number]
 CHECK ( ISNUMERIC(JSON_VALUE(value, '$.age'))>0 )

 ALTER TABLE Person
 ADD CONSTRAINT [Person should have skills]
 CHECK ( JSON_QUERY(value, '$.skills') IS NOT NULL)
First constraint will take the value of $.age property and check is this numeric value. Second constraint will try to find JSON object in $.skills property and verify that it exists. The following INSERT statements will fail due to the violation of constraints:

INSERT INTO Person(value)
 VALUES ('{"age": "not a number", "skills":[]}')

 INSERT INTO Person(value)
 VALUES ('{"age": 35}')

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

Сжатом формате JSON Если у вас есть большой текст в JSON можно явно сжатия текста JSON с использованием встроенной функции сжатия. В следующем примере сжатый контент в формате JSON хранится в виде двоичных данных, и у нас есть вычисляемый столбец, распаковать JSON, как исходный текст, используя распаковки функцией:

CREATE TABLE Person

 ( _id int identity constraint PK_JSON_ID primary key,

 data varbinary(max),

 value AS CAST(DECOMPRESS(data) AS nvarchar(max))

 )

 INSERT INTO Person(data)

 VALUES (COMPRESS(@json))

Сжимать и разжимать функции используют стандарт сжатия gzip. Если ваш клиент может обрабатывать сжатие gzip (электронная.браузер G, который понимает содержание с помощью gzip), вы можете сразу вернуть сжатый контент. Обратите внимание, что это производительность/торговля-выключено для хранения. Если вы часто сжатых данных запроса вы МиГ иметь меньшую производительность, потому что текст должен быть распакованы каждый раз.

Примечание: функции JSON доступны только в SQL сервере 2016+ и база данных SQL.

Подробнее можно прочитать из источника данной статьи

https://blogs.msdn.microsoft.com/sqlserverstorageengine/2015/11/23/storing-json-in-sql-server/

Комментарии (0)

Вопрос, который вы должны задать:

я привязан к этой базе?

Делать

  1. Если вы можете использовать разные базы данных для хранения JSON, можно использовать раствор для хранения документов, таких как CouchDB, для DynamoDB или в MongoDB.
  2. Использование этих документов для хранения БД'ы возможность индексирования и поиска иерархических данных.
  3. Использование реляционной базы данных для реляционных данных.
  4. Использование реляционных баз данных для отчетности, хранилищ данных и интеллектуального анализа данных.

ДОН'Т

  1. Хранить JSON как строку, если это возможно.
  2. Попробовать и придумать максимальная длина данных JSON.
  3. Используйте varchar для хранения JSON (использование текста/объекта, если необходимо).
  4. Попробуйте поиск через хранить JSON для ценностей.
  5. Беспокоиться о побеге JSON, чтобы хранить как строку.
Комментарии (1)

В "золотое правило" Я использую, в руке-волнистые смысле, что если мне нужен JSON в своем формате RAW, это'ы хорошо для хранения. Если мне придется сделать специальную точку разбора, то это's не.

Например, если я'м создания API, который отправляет сырые JSON, и по какой-то причине это значение разве'т собираюсь менять, то это'ы ладно чтобы сохранить его как сырые JSON. Если мне придется разобрать его, изменить его, обновить его и т. д... тогда не так уж много.

Комментарии (0)

В JSON's не большой в relationional дБ'ов. Если вы разложите JSON в столбцы и магазин в дБ , это'ы большой, но хранить JSON в объект дальше, чтобы использовать его в качестве системы архивирования данных.

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

Кроме того , большая часть обработки JSON если на все поле был запрос будет вне среды SQL как SQL-это просто не предназначены для обработки в JSON. Тогда реально возникает вопрос , Где хранить этот JSON, я просто пусть это будет как плоские файлы и при необходимости запрашивать их через другие системы (СПАРК/куст/и т. д.).

Я бы согласился с вашим художником ДБ , Дон'т использовать РСУБД для архивирования. Есть более дешевые варианты. Также BLOB-объектов в JSON может получить огромный и может начать заболачивания вниз диск ДБ пространстве с течением времени.

Комментарии (0)

PostgreSQL имеет встроенный JSON и тип данных JSONB

Эти несколько примеров:

CREATE TABLE orders (
 ID serial NOT NULL PRIMARY KEY,
 info json NOT NULL
);

INSERT INTO orders (info)
VALUES
 (
 '{ "customer": "Lily Bush", "items": {"product": "Diaper","qty": 24}}'
 ),
 (
 '{ "customer": "Josh William", "items": {"product": "Toy Car","qty": 1}}'
 ),
 (
 '{ "customer": "Mary Clark", "items": {"product": "Toy Train","qty": 2}}'
 );

PostgreSQL предоставляет два родных операторов-и GT; " и " - >> на запрос JSON-данных.

Возвращает оператор-> `JSON в поле объект по ключу.

Оператор-> возвращается и GT;` JSON в поле Объект текст.

SELECT
 info -> 'customer' AS customer
FROM
 orders;

SELECT
 info ->> 'customer' AS customer
FROM
 orders
WHERE
 info -> 'items' ->> 'product' = 'Diaper'
Комментарии (0)