web-dev-qa-db-ja.com

JSONテーブルまたはXMLデータをSQLテーブルに保存できるのはいつですか

SQLまたはMySQL(またはその点でリレーショナルDB)を使用する場合-通常の列にデータを保存することは、インデックス作成などの目的に適していることを理解しています...

問題は、JSONデータのロードと保存がはるかに簡単な場合があることです。開発が容易になります。

未加工のJSONデータをDBに保存するための「ゴールデンルール」はありますか?

そうすることは絶対に間違った練習ですか?

概要

非常に良い答えが出されましたが、間違いなく最もよく組織化されているのは、賞金に値する@Shnugoによって与えられた答えです。

また、@ Gordon Linoffと@Amresh Pandeyが他の特別なユースケースを説明するために与えた回答を指摘したいと思います。

神に感謝し、みんなお疲れ様でした!

49
levi

コメントするには長すぎます。

「絶対に間違っている」場合、ほとんどのデータベースはそれをサポートしません。さて、ほとんどのデータベースはFROM句でカンマをサポートしており、「絶対に間違っている」と考えています。ただし、JSONのサポートは新しい開発であり、下位互換性のある「機能」ではありません。

明らかなケースの1つは、JSON構造体がアプリケーションに返される単純なBLOBである場合です。その後、議論はありません-JSONを保存するオーバーヘッド以外は、すべてのレコードに共通のフィールドを持つ構造化データでは不必要に冗長です。

別のケースは、「スパース」列のケースです。多くの列が可能な行がありますが、これらは行ごとに異なります。

別のケースは、「ネストされた」レコードをレコードに保存する場合です。 JSONは強力です。

JSONにクエリ対象のレコード間で共通のフィールドがある場合は、通常、これらを適切なデータベース列に配置することをお勧めします。ただし、データは複雑であり、JSONなどの形式の場所があります。

12
Gordon Linoff

魔法の杖を振る。失礼! JSONの使用に関するゴールデンルール:

  • MySQLがJSONをinside見る必要がなく、アプリケーションが単にもののコレクションを必要とする場合、JSONは大丈夫です。

  • and内にあるデータを検索する場合、MariaDB 10.0.1またはMySQL 5.7(JSONデータ型と関数を使用)、JSONmightが実用的です。 MariaDB 5.3の「動的」列はこれの変形です。

  • 「Entity-Attribute-Value」などを実行している場合、JSONは良くありませんが、それはいくつかの悪の中で最も小さいものです。 http://mysql.rjweb.org/doc.php/eav

  • インデックス付きの列で検索する場合、JSONに値が埋め込まれていないことは大きなプラスです。

  • インデックス付き列の範囲、またはFULLTEXT検索またはSPATIALで検索する場合、JSONは使用できません。

  • WHERE a=1 AND b=2の場合、「複合」インデックスINDEX(a,b)は素晴らしいです。おそらくJSONには近づかないでしょう。

  • JSONは「スパース」データでうまく機能します。 INDEXingは機能しますが、そうではありません。 (多くの行で「欠落」またはNULLの値を参照しています。)

  • JSONは、余分なテーブルに頼ることなく、「配列」と「ツリー」を提供できます。しかし、そのような配列/ツリーを掘るonlyアプリでは、not SQL。

  • JSONはXMLよりも優れています。 (私の意見)

  • アプリ以外からJSON文字列を取得したくない場合は、BLOBへの格納として(クライアントで)圧縮することをお勧めします。 .jpgのようなものだと考えてください。そこには何かがありますが、SQLは気にしません。

アプリケーションを記述してください。より具体的にすることができます。

11
Rick James

新しい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 )
 )

この単純な構造は、JSONを表すIDと値を表すキーのみを持っているNoSQLデータベース(Azure DocumentDBやMongoDBなど)で作成できる標準のNoSQLコレクションに似ています。

NVARCHARは単なるテキストではないことに注意してください。 SQL Serverには、ディスクに格納されているデータを透過的に圧縮できるテキスト圧縮メカニズムが組み込まれています。圧縮は言語に依存し、データに応じて最大50%になります(UNICODE圧縮を参照)。

SQLサーバーと他のプレーンなNoSQLデータベースの主な違いは、SQL Serverでは複数のJSONオブジェクトを同じ「コレクション」に保存し、それらを通常のリレーショナル列と結合できるハイブリッドデータモデルを使用できることです。

例として、コレクション内のすべての人がFirstNameとLastNameを持ち、その人に関する一般的な情報を1つの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列にのみCHECK制約を追加しました)。

この構造を標準のNoSQLコレクションと比較すると、強く型付けされたデータ(FirstNameおよびLastName)へのアクセスが速くなることに気付くかもしれません。したがって、このソリューションは、すべてのオブジェクトにわたって繰り返される情報を識別でき、他の変数情報をJSONとして格納できるハイブリッドモデルに適しています。これにより、柔軟性とパフォーマンスを組み合わせることができます。

この構造をPersonテーブルAdventureWorksデータベースのスキーマと比較すると、多くの関連テーブルが削除されていることがわかります。

スキーマが単純であることに加えて、データアクセス操作は、複雑なリレーショナル構造に比べて単純になります。これで、複数のテーブルを結合する代わりに、単一のテーブルを読み取ることができます。関連情報(電子メールアドレス、電話番号)を持つ新しい人物を挿入する必要がある場合、AdventureWorks Personテーブルに1つのレコードを挿入する代わりに1つのテーブルに1つのレコードを挿入し、ID列を取得して電話の保存に使用される外部キーを見つけることができます、電子メールアドレスなど。さらに、このモデルでは、外部キー関係を使用してカスケード削除することなく、1人の行を簡単に削除できます。

NoSQLデータベースは、単純な読み取り、挿入、および削除操作向けに最適化されています。SQLServer 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}')

CHECK制約は挿入/更新プロセスの速度を低下させる可能性があるため、書き込みパフォーマンスの高速化が必要な場合はチェック制約を回避する可能性があることに注意してください。

圧縮されたJSONストレージ大きなJSONテキストがある場合は、組み込みのCOMPRESS機能を使用してJSONテキストを明示的に圧縮できます。次の例では、圧縮されたJSONコンテンツはバイナリデータとして保存され、DECOMPRESS関数を使用して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))

COMPRESSおよびDECOMPRESS関数は、標準のGZip圧縮を使用します。クライアントがGZip圧縮(gzipコンテンツを理解するブラウザなど)を処理できる場合、圧縮されたコンテンツを直接返すことができます。これはパフォーマンスとストレージのトレードオフであることに注意してください。圧縮データを頻繁にクエリする場合、毎回テキストを圧縮解除する必要があるため、migのパフォーマンスは低下します。

注:JSON関数は、SQL Server 2016+およびAzure SQL Databaseでのみ使用できます。

この記事のソースからより多くを読むことができます

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

9
AMRESH PANDEY

私が使用する「黄金律」は、手で振る舞いながら、JSONをそのままの形式で必要とする場合、保存しても大丈夫です。解析の特別なポイントを作成する必要がある場合、そうではありません。

たとえば、未加工のJSONを送信するAPIを作成していて、何らかの理由でこの値が変更されない場合、未加工のJSONとして保存するのはokayです。解析、変更、更新などが必​​要な場合は、それほどではありません。

4
piisexactly3

あなたが尋ねなければならない質問は次のとおりです。

このデータベースのみを使用することに縛られていますか?

行う

  1. 別のデータベースを使用してJSONを保存できる場合は、CouchDB、DynamoDB、MongoDBなどのドキュメントストレージソリューションを使用します。
  2. これらのドキュメントストレージDBの機能を使用して、階層データにインデックスを付けて検索します。
  3. リレーショナルデータにリレーショナルデータベースを使用します。
  4. レポート作成、データウェアハウジング、データマイニングにリレーショナルデータベースを使用します。

しないでください

  1. 可能であれば、JSONを文字列として保存します。
  2. JSONデータの最大長を試してみてください。
  3. Varcharを使用してJSONを保存します(必要な場合はtext/blobを使用します)。
  4. 保存されたJSONで値を検索してみてください。
  5. JSONをエスケープして文字列として保存するのが心配です。
4
Anand

Jsonはリレーショナルデータベースでは優れていません。 jsonを列に展開してdbに保存するのは素晴らしいことですが、jsonをblobとして保存することは、データアーカイブシステムとして使用することになります。

Jsonを展開せずに単一の列に格納する理由はいくつかありますが、そのjsonフィールドの値がクエリに使用されない(または値が既に列に展開されている)として決定が下されます。

また、フィールドがクエリされた場合のjson処理のほとんどは、sqlがjson処理を目的としていないため、sql環境の外部にあります。本当の質問は、になります。ここで、このjsonを保存し、フラットファイルとして保存し、必要に応じて他のシステム(spark/Hive/etc)で照会します。

DBアーティストに同意します。アーカイブにRDBMSを使用しないでください。より安価なオプションがあります。また、json blobは巨大になり、時間とともにDBディスク領域を使い果たしてしまう可能性があります。

2
Satyadev

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には、JSONデータをクエリするための2つのネイティブ演算子->および->>が用意されています。

演算子->は、キーごとにJSONオブジェクトフィールドを返します。

演算子->>は、JSONオブジェクトフィールドをテキストで返します。

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

SELECT
 info ->> 'customer' AS customer
FROM
 orders
WHERE
 info -> 'items' ->> 'product' = 'Diaper'
0