Dukungan JSON asli di MYSQL 5.7: apa pro dan kontra tipe data JSON di MYSQL?

113

Di MySQL 5.7, tipe data baru untuk menyimpan data JSON di tabel MySQL telah ditambahkan. Ini jelas akan menjadi perubahan besar di MySQL. Mereka mendaftar beberapa manfaat

Validasi Dokumen - Hanya dokumen JSON yang valid yang dapat disimpan di kolom JSON, sehingga Anda mendapatkan validasi otomatis untuk data Anda.

Akses Efisien - Lebih penting lagi, ketika Anda menyimpan dokumen JSON di kolom JSON, itu tidak disimpan sebagai nilai teks biasa. Sebaliknya, ini disimpan dalam format biner yang dioptimalkan yang memungkinkan akses lebih cepat ke anggota objek dan elemen array.

Kinerja - Tingkatkan kinerja kueri Anda dengan membuat indeks pada nilai dalam kolom JSON. Ini dapat dicapai dengan "indeks fungsional" pada kolom virtual.

Kenyamanan - Sintaks sebaris tambahan untuk kolom JSON membuatnya sangat alami untuk mengintegrasikan kueri Dokumen dalam SQL Anda. Misalnya (features.feature adalah kolom JSON):SELECT feature->"$.properties.STREET" AS property_street FROM features WHERE id = 121254;

WOW ! mereka menyertakan beberapa fitur hebat. Sekarang lebih mudah untuk memanipulasi data. Sekarang dimungkinkan untuk menyimpan data yang lebih kompleks dalam kolom. Jadi MySQL sekarang dibumbui dengan NoSQL.

Sekarang saya bisa membayangkan kueri untuk data JSON seperti

SELECT * FROM t1
WHERE JSON_EXTRACT(data,"$.series") IN 
( 
SELECT JSON_EXTRACT(data,"$.inverted") 
FROM t1 | {"series": 3, "inverted": 8} 
WHERE JSON_EXTRACT(data,"$.inverted")<4 );

Jadi dapatkah saya menyimpan relasi kecil yang sangat besar dalam beberapa json colum? Apakah itu bagus Apakah itu merusak normalisasi. Jika ini memungkinkan maka saya kira itu akan bertindak seperti NoSQL di kolom MySQL . Saya sangat ingin tahu lebih banyak tentang fitur ini. Pro dan kontra tipe data MySQL JSON.

Imran
sumber
oh tolong jangan katakan apa yang saya pikir Anda katakan. Sini, baca ini . Milik Anda adalah varian lain dari ide buruk.
Drew
@Drew Anda memberikan jawaban besar. Tapi itu bukan pertanyaanku. Saya hanya ingin tahu bahwa jika kita menulis kueri untuk data json maka kita dapat melewati aturan sql. karena kita tidak membutuhkan banyak tabel
Imran
1
katamu Now it is possible to store more complex data in column. Hati-hati
Drew
2
Indeks dukungan tipe data Json dan memiliki ukuran pintar: 64K & 4G. Jadi apa masalahnya jika saya ingin menyimpan 2000 data dan menambahkan 5 label bersarang, bukan 5 tabel dengan relasi?
Imran
5
"Saya sangat ingin tahu lebih banyak tentang fitur ini." dan "Pro dan kontra tipe data MySQL JSON." bukanlah pertanyaan, dan jika diutarakan ulang sebagai pertanyaan yang terlalu luas. "Jadi saya tidak pernah memikirkan struktur skema yang rumit dan kunci asing di MySQL. Saya menyimpan relasi yang rumit hanya dengan menggunakan beberapa tabel." kontradiktif karena JSON bukan relasi & FK. Penjelasan tentang "apakah ini bagus" hanyalah pengantar model relasional, jadi sekali lagi ini terlalu luas. Pelajari beberapa contoh, buat daftar pro & kontra Anda sendiri dengan referensi, dan tanyakan di mana kesalahan Anda.
philipxy

Jawaban:

57
SELECT * FROM t1
WHERE JSON_EXTRACT(data,"$.series") IN ...

Menggunakan kolom di dalam ekspresi atau fungsi seperti ini merusak peluang kueri yang menggunakan indeks untuk membantu mengoptimalkan kueri. Kueri yang ditampilkan di atas dipaksa untuk melakukan pemindaian tabel.

Klaim tentang "akses efisien" menyesatkan. Artinya, setelah kueri memeriksa baris dengan dokumen JSON, kueri dapat mengekstrak bidang tanpa harus mengurai teks sintaks JSON. Tapi masih membutuhkan pemindaian tabel untuk mencari baris. Dengan kata lain, kueri harus memeriksa setiap baris.

Dengan analogi, jika saya menelusuri buku telepon untuk orang-orang dengan nama depan "Bill", saya masih harus membaca setiap halaman di buku telepon, bahkan jika nama depan telah disorot agar sedikit lebih cepat untuk menemukannya.

MySQL 5.7 memungkinkan Anda untuk menentukan kolom virtual di tabel, dan kemudian membuat indeks di kolom virtual.

ALTER TABLE t1
  ADD COLUMN series AS (JSON_EXTRACT(data, '$.series')),
  ADD INDEX (series);

Kemudian jika Anda membuat kueri kolom virtual, itu dapat menggunakan indeks dan menghindari pemindaian tabel.

SELECT * FROM t1
WHERE series IN ...

Ini bagus, tapi agak melenceng dari penggunaan JSON. Bagian yang menarik dari penggunaan JSON adalah memungkinkan Anda untuk menambahkan atribut baru tanpa harus melakukan ALTER TABLE. Tetapi ternyata Anda harus menentukan kolom tambahan (virtual), jika Anda ingin mencari bidang JSON dengan bantuan indeks.

Namun Anda tidak perlu menentukan kolom dan indeks virtual untuk setiap kolom di dokumen JSON — hanya yang ingin Anda telusuri atau urutkan. Mungkin ada atribut lain di JSON yang hanya perlu Anda ekstrak dalam daftar-pilih seperti berikut:

SELECT JSON_EXTRACT(data, '$.series') AS series FROM t1
WHERE <other conditions>

Saya biasanya akan mengatakan bahwa ini adalah cara terbaik untuk menggunakan JSON di MySQL. Hanya di daftar-pilih.

Saat Anda mereferensikan kolom dalam klausa lain (JOIN, WHERE, GROUP BY, HAVING, ORDER BY), lebih efisien menggunakan kolom konvensional, bukan bidang dalam dokumen JSON.

Saya mempresentasikan ceramah berjudul Bagaimana Menggunakan JSON di MySQL Salah di konferensi Percona Live pada bulan April 2018. Saya akan memperbarui dan mengulangi ceramah di Oracle Code One pada musim gugur.

Ada masalah lain dengan JSON. Misalnya, dalam pengujian saya dibutuhkan 2-3 kali lebih banyak ruang penyimpanan untuk dokumen JSON dibandingkan dengan kolom konvensional yang menyimpan data yang sama.

MySQL mempromosikan kemampuan JSON baru mereka secara agresif, sebagian besar untuk mencegah orang bermigrasi ke MongoDB. Tetapi penyimpanan data berorientasi dokumen seperti MongoDB pada dasarnya adalah cara non-relasional untuk mengatur data. Ini berbeda dengan relasional. Saya tidak mengatakan satu lebih baik dari yang lain, itu hanya teknik yang berbeda, cocok untuk berbagai jenis kueri.

Anda harus memilih untuk menggunakan JSON saat JSON membuat kueri Anda lebih efisien.

Jangan memilih teknologi hanya karena itu baru, atau demi fashion.


Sunting: Implementasi kolom virtual di MySQL seharusnya menggunakan indeks jika klausa WHERE Anda menggunakan ekspresi yang persis sama dengan definisi kolom virtual. Artinya, berikut ini harus menggunakan indeks pada kolom virtual, karena kolom virtual ditentukanAS (JSON_EXTRACT(data,"$.series"))

SELECT * FROM t1
WHERE JSON_EXTRACT(data,"$.series") IN ...

Kecuali saya telah menemukan dengan menguji fitur ini bahwa itu TIDAK berfungsi karena alasan tertentu jika ekspresi adalah fungsi ekstraksi JSON. Ini berfungsi untuk jenis ekspresi lain, hanya saja fungsi JSON tidak.

Bill Karwin
sumber
7
Layak mengikuti tautan ke slide
Paul Campbell
Poin bagusnya 2 teknologi sama-sama bagus artinya kami memutuskan mana yang sesuai dengan kebutuhan kami dan apa yang memberi kami lebih banyak keuntungan dalam hal keamanan dan kinerja.
Christopher Pelayo
1
Inti masalahnya adalah bahwa ALTER TABLE masih diperlukan untuk menggunakan indeks pada kolom yang dihasilkan untuk setiap kunci baru di JSON. Senang melihatnya ditunjukkan.
pengguna1454926
Hanya jika Anda perlu menambahkan kolom virtual dan / atau indeks. Jika Anda memperlakukan data JSON sebagai "kotak hitam" dan tidak mencoba melakukan kueri apa pun yang menelusuri atau mengurutkan pada sub-bidang dalam JSON, Anda tidak perlu melakukannya. Itu sebabnya saya merekomendasikan untuk menghindari merujuk JSON JOIN, WHEREatau klausul lainnya. Ambil saja kolom JSON di daftar-pilih.
Bill Karwin
Tautan ke slide rusak, @BillKarwin.
lakeare
43

Yang berikut dari MySQL 5.7 membawa kembali seksi dengan JSON terdengar bagus bagi saya:

Menggunakan Jenis Data JSON di MySQL hadir dengan dua keunggulan dibandingkan menyimpan string JSON dalam bidang teks:

Validasi data. Dokumen JSON akan secara otomatis divalidasi dan dokumen yang tidak valid akan menghasilkan kesalahan. Format penyimpanan internal yang ditingkatkan. Data JSON diubah ke format yang memungkinkan akses baca cepat ke data dalam format terstruktur. Server dapat mencari subobjek atau nilai bertingkat berdasarkan kunci atau indeks, yang memungkinkan fleksibilitas dan kinerja tambahan.

...

Ragam khusus penyimpanan NoSQL (DB Dokumen, Penyimpanan nilai kunci, dan DB Grafik) mungkin merupakan opsi yang lebih baik untuk kasus penggunaan spesifiknya, tetapi penambahan jenis data ini memungkinkan Anda mengurangi kompleksitas tumpukan teknologi Anda. Harganya digabungkan ke database MySQL (atau yang kompatibel). Tapi itu bukan masalah bagi banyak pengguna.

Perhatikan bahasa tentang validasi dokumen karena ini merupakan faktor penting. Saya kira serangkaian tes perlu dilakukan untuk perbandingan dari dua pendekatan. Kedua makhluk itu:

  1. Mysql dengan tipe data JSON
  2. Mysql tanpa

Net memiliki tapi slideshow dangkal seperti sekarang pada topik mysql / json / performance dari apa yang saya lihat.

Mungkin postingan Anda bisa menjadi penghubungnya. Atau mungkin kinerja adalah pemikiran setelahnya, tidak yakin, dan Anda hanya bersemangat untuk tidak membuat banyak tabel.

Drew
sumber
7
Satu penipu; Tipe data JSON tidak didukung oleh tabel Memori Mysql, seperti tipe data, TEXT & BLOB. Ini berarti jika tabel sementara diperlukan, itu akan membuat tabel berbasis disk bukan memori. Beberapa kasus ketika tabel sementara digunakan diuraikan di sini: dev.mysql.com/doc/refman/5.7/en/internal-temporary-tables.html
media
1
@ Raizmedia Bisakah Anda menjelaskan mengapa tabel berbasis disk adalah masalah vs memori (saya kira tabel berbasis)?
lapin
@lapin Mungkin karena keterbatasan kecepatan.
Little Helper
@LittleHelper Anda dapat menghindarinya jika Anda menggunakan slot PCI 4x 40 Gb / s M.2 dan memasukkan drive yang didukung 40 Gb / s. Ini bekerja secepat memmory. Anda juga dapat menerapkan format khusus ke drive yang digunakan untuk memformat memmory.
Sergey Romanov
@SergeyRomanov, [citation required]Sudahkah Anda membandingkan drive itu dengan RAM?
Bill Karwin
11

Saya mengalami masalah ini baru-baru ini, dan saya menyimpulkan pengalaman berikut:

1, Tidak ada cara untuk menyelesaikan semua pertanyaan. 2, Anda harus menggunakan JSON dengan benar.

Satu kasus:

Saya memiliki sebuah tabel bernama:, CustomFielddan harus ada dua kolom: name, fields. nameadalah string yang dilokalkan, isinya harus seperti:

{
  "en":"this is English name",
  "zh":"this is Chinese name"
   ...(other languages)
}

Dan fieldsseharusnya seperti ini:

[
  {
    "filed1":"value",
    "filed2":"value"
    ...
  },
  {
    "filed1":"value",
    "filed2":"value"
    ...
  }
  ...
]

Seperti yang Anda lihat, baik the namedan the fieldsdapat disimpan sebagai JSON, dan berhasil!

Namun, jika saya sering menggunakan nameuntuk mencari tabel ini, apa yang harus saya lakukan? Gunakan JSON_CONTAINS, JSON_EXTRACT...? Jelas, itu bukan ide yang baik untuk menyimpannya sebagai JSON lagi, kita harus menyimpannya ke sebuah meja yang independen: CustomFieldName.

Dari kasus di atas, saya pikir Anda harus mengingat ide-ide ini:

  1. Mengapa MYSQL mendukung JSON?
  2. Mengapa Anda ingin menggunakan JSON? Apakah logika bisnis Anda hanya membutuhkan ini? Atau ada yang lain?
  3. Jangan pernah malas

Terima kasih

Bruce
sumber
2
Anda mungkin tertarik menggunakan kolom VIRTUAL. percona.com/blog/2016/03/07/…
Bel
10

Dari pengalaman saya, implementasi JSON setidaknya di MySql 5.7 tidak terlalu berguna karena kinerjanya yang buruk. Yah, tidak terlalu buruk untuk membaca data dan validasi. Namun, modifikasi JSON 10-20 kali lebih lambat dengan MySql yang menggunakan Python atau PHP. Mari kita bayangkan JSON yang sangat sederhana:

{ "name": "value" }

Misalkan kita harus mengubahnya menjadi seperti itu:

{ "name": "value", "newName": "value" }

Anda dapat membuat skrip sederhana dengan Python atau PHP yang akan memilih semua baris dan memperbaruinya satu per satu. Anda tidak dipaksa untuk melakukan satu transaksi besar untuk itu, sehingga aplikasi lain dapat menggunakan tabel tersebut secara paralel. Tentu saja, Anda juga dapat melakukan satu transaksi besar jika Anda mau, jadi Anda akan mendapat jaminan bahwa MySql akan melakukan "semua atau tidak sama sekali", tetapi aplikasi lain kemungkinan besar tidak dapat menggunakan database selama eksekusi transaksi.

Saya memiliki 40 juta tabel baris, dan skrip Python memperbaruinya dalam 3-4 jam.

Sekarang kami memiliki MySql JSON, jadi kami tidak membutuhkan Python atau PHP lagi, kami dapat melakukan hal seperti itu:

UPDATE `JsonTable` SET `JsonColumn` = JSON_SET(`JsonColumn`, "newName", JSON_EXTRACT(`JsonColumn`, "name"))

Ini terlihat sederhana dan luar biasa. Namun, kecepatannya 10-20 kali lebih lambat dari versi Python, dan ini adalah transaksi tunggal, sehingga aplikasi lain tidak dapat mengubah data tabel secara paralel.

Jadi, jika kita ingin menduplikasi kunci JSON dalam tabel 40 juta baris, kita tidak perlu menggunakan tabel sama sekali selama 30-40 jam. Itu tidak masuk akal.

Tentang membaca data, dari pengalaman saya akses langsung ke lapangan JSON melalui JSON_EXTRACTdi WHEREjuga terkenal lambat (jauh lebih lambat yang TEXTdengan LIKEatas tidak diindeks kolom). Kolom yang dibuat secara virtual bekerja lebih cepat, namun, jika kita mengetahui struktur data kita sebelumnya, kita tidak memerlukan JSON, kita dapat menggunakan kolom tradisional sebagai gantinya. Ketika kami menggunakan JSON yang sangat berguna, yaitu ketika struktur data tidak diketahui atau sering berubah (misalnya, pengaturan plugin kustom), pembuatan kolom virtual secara teratur untuk setiap kolom baru yang mungkin tidak terlihat seperti ide yang bagus.

Python dan PHP membuat validasi JSON seperti pesona, jadi patut dipertanyakan apakah kita membutuhkan validasi JSON di sisi MySql sama sekali. Mengapa tidak juga memvalidasi XML, dokumen Microsoft Office atau memeriksa ejaan? ;)

Vitalii
sumber