MYSQL 5.7'de yerel JSON desteği: MYSQL'deki JSON veri türünün artıları ve eksileri nelerdir?


114

MySQL 5.7'de JSON verilerini MySQL tablolarında depolamak için yeni bir veri türü eklenmiştir. Açıkçası MySQL'de büyük bir değişiklik olacak. Bazı faydaları listelediler

Belge Doğrulama - Yalnızca geçerli JSON belgeleri bir JSON sütununda saklanabilir, böylece verilerinizin otomatik olarak doğrulanmasını sağlarsınız.

Verimli Erişim - Daha da önemlisi, bir JSON belgesini bir JSON sütununda sakladığınızda, düz metin değeri olarak depolanmaz. Bunun yerine, nesne üyelerine ve dizi öğelerine daha hızlı erişim sağlayan optimize edilmiş bir ikili biçimde depolanır.

Performans - JSON sütunlarındaki değerler üzerinde dizinler oluşturarak sorgu performansınızı artırın. Bu, sanal sütunlardaki "işlevsel indeksler" ile elde edilebilir.

Kolaylık - JSON sütunları için ek satır içi sözdizimi, Belge sorgularını SQL'inize entegre etmeyi çok doğal hale getirir. Örneğin (features.feature bir JSON sütunudur):SELECT feature->"$.properties.STREET" AS property_street FROM features WHERE id = 121254;

VAOV ! bazı harika özellikler içerirler. Artık verileri işlemek daha kolay. Artık daha karmaşık verileri sütunda saklamak mümkün. Yani MySQL artık NoSQL ile tatlandırılmıştır.

Şimdi JSON verileri için bir sorgu hayal edebiliyorum.

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 );

Yani birkaç json colum'da büyük küçük ilişkileri depolayabilir miyim? İyi mi? Normalleşmeyi bozuyor mu? Bu mümkünse, sanırım bir MySQL sütunundaki NoSQL gibi davranacaktır . Bu özellik hakkında gerçekten daha fazla bilgi edinmek istiyorum. MySQL JSON veri türünün artıları ve eksileri.


lütfen söylediğini düşündüğüm şeyi söyleme. İşte, bunu oku . Sizinki, kötü bir fikrin başka bir çeşididir.
Drew

@Drew Büyük bir cevap verdin. Ama bu benim sorum değil. Sadece, json verileri için bir sorgu yazarsak, sql kurallarını atlayabileceğimizi bilmek istiyorum. çünkü çok fazla masaya ihtiyacımız yok
Imran

1
dedin Now it is possible to store more complex data in column. Dikkatli olun
Drew

2
Json veri türü destek endeksi ve akıllı boyuta sahiptir: 64K ve 4G. Peki 2000 veriyi depolamak ve 5 tablo yerine 5 iç içe etiket eklemek istersem sorun ne olur?
Imran

5
"Bu özellik hakkında gerçekten daha fazla bilgi edinmek istiyorum." ve "MySQL JSON veri türünün artıları ve eksileri." sorular değildir ve sorular çok geniş olduğu için yeniden ifade edilirse. "Bu nedenle, MySQL'de karmaşık bir şema yapısı ve yabancı anahtarlar düşünmüyorum. Yalnızca birkaç tablo kullanarak karmaşık ilişkileri depoluyorum." JSON, ilişkiler ve FK'ler olmadığı için kendisiyle çelişir. "Bu kadar iyi mi" açıklaması sadece ilişkisel modele bir giriştir, bu yüzden yine bu çok geniş. Bazı örnekler üzerinde çalışın, referanslarla kendi artı ve eksiler listenizi yapın ve nerede yanlış yaptığınızı sorun.
philipxy

Yanıtlar:


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

Bir ifade veya bunun gibi bir işlev içinde bir sütun kullanmak, sorguyu optimize etmeye yardımcı olmak için bir dizin kullanma olasılığını ortadan kaldırır. Yukarıda gösterilen sorgu bir tablo taraması yapmaya zorlanır.

"Etkin erişim" iddiası yanıltıcıdır. Bu, sorgu bir JSON belgesine sahip bir satırı inceledikten sonra, JSON sözdiziminin metnini ayrıştırmak zorunda kalmadan bir alanı çıkarabileceği anlamına gelir. Ancak satırları aramak için yine de bir tablo taraması gerekir. Diğer bir deyişle, sorgu her satırı incelemelidir.

Benzetme yapmak gerekirse, adı "Bill" olan kişiler için bir telefon rehberi arıyorsam, onları fark etmeyi biraz daha hızlı hale getirmek için ilk isimler vurgulanmış olsa bile, telefon rehberindeki her sayfayı okumam gerekir.

MySQL 5.7, tabloda sanal bir sütun tanımlamanıza ve ardından sanal sütun üzerinde bir dizin oluşturmanıza izin verir.

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

Ardından, sanal sütunu sorgularsanız, dizini kullanabilir ve tablo taramasından kaçınabilir.

SELECT * FROM t1
WHERE series IN ...

Bu güzel, ancak JSON kullanma noktasını kaçırıyor. JSON kullanmanın çekici yanı, ALTER TABLE yapmak zorunda kalmadan yeni özellikler eklemenize izin vermesidir. Ancak, JSON alanlarını bir indeks yardımıyla aramak istiyorsanız, yine de fazladan (sanal) bir sütun tanımlamanız gerekir.

Ancak , JSON belgesindeki her alan için sanal sütunlar ve dizinler tanımlamanız gerekmez - yalnızca aramak veya sıralamak istedikleriniz. JSON'da yalnızca aşağıdaki gibi seçme listesinde çıkarmanız gereken başka öznitelikler olabilir:

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

Genel olarak JSON'u MySQL'de kullanmanın en iyi yolu olduğunu söyleyebilirim. Yalnızca seçilen listede.

Diğer cümlelerde (JOIN, WHERE, GROUP BY, HAVING, ORDER BY) sütunlara başvurduğunuzda, JSON belgelerindeki alanları değil, geleneksel sütunları kullanmak daha etkilidir.

Nisan 2018'de Percona Live konferansında MySQL'de JSON Nasıl Kullanılır başlıklı bir konuşma sundum. Sonbaharda Oracle Code One'daki konuşmayı güncelleyip tekrar edeceğim.

JSON ile ilgili başka sorunlar var. Örneğin, benim testlerimde JSON belgeleri için aynı verileri depolayan geleneksel sütunlara kıyasla 2-3 kat daha fazla depolama alanı gerektiriyordu.

MySQL, insanları MongoDB'ye geçmeye karşı caydırmak için yeni JSON yeteneklerini agresif bir şekilde destekliyor. Ancak MongoDB gibi belge odaklı veri depolama, temelde verileri organize etmenin ilişkisel olmayan bir yoludur. İlişkiselden farklı. Birinin diğerinden daha iyi olduğunu söylemiyorum, bu sadece farklı türde sorgulara uygun farklı bir teknik.

JSON, sorgularınızı daha verimli hale getirdiğinde JSON kullanmayı seçmelisiniz.

Bir teknolojiyi sadece yeni olduğu için veya moda uğruna seçmeyin.


Düzenleme: MySQL'deki sanal sütun uygulamasının, WHERE yan tümceniz sanal sütunun tanımıyla tam olarak aynı ifadeyi kullanması durumunda dizini kullanması beklenir. Olduğunu, şu olmalıdır sanal sütun tanımlanmış olduğundan, sanal sütun üzerinde dizin kullanabilirsinizAS (JSON_EXTRACT(data,"$.series"))

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

Ancak, bu özelliği test ederek, ifade bir JSON çıkarma işlevi ise herhangi bir nedenle çalışmadığını buldum. Diğer ifade türleri için çalışır, JSON işlevleri için değil.


7
Slaytların bağlantısını takip etmeye değer
Paul Campbell

İyi bir nokta, 2 teknolojinin her ikisi de kendi başlarına iyi, yani hangisinin ihtiyaçlarımıza uyacağına ve güvenlik ve performans açısından bize neyin daha fazla avantaj sağlayacağına karar veriyoruz.
Christopher Pelayo

1
Sorunun özü, JSON'daki her yeni anahtar için oluşturulan bir sütundaki bir dizinden yararlanmak için ALTER TABLE'ın hala gerekli olmasıdır. Gösterildiğine sevindim.
user1454926

Yalnızca sanal bir sütun ve / veya bir dizin eklemeniz gerekiyorsa. JSON verilerini bir "kara kutu" olarak ele alırsanız ve JSON içindeki alt alanları arayan veya sıralayan herhangi bir sorgu yapmaya çalışmazsanız, bunu yapmanız gerekmez. Ben de JSON başvuran önlemek için tavsiye nedeni budur JOIN, WHEREya da diğer maddeleri. Seçme listesindeki JSON sütununu getirmeniz yeterlidir.
Bill Karwin

Slaytların bağlantısı kesildi, @BillKarwin.
lakesare

43

MySQL 5.7'den gelenler , JSON ile seksi geri getiriyor bana iyi geliyor:

MySQL'de JSON Veri Türünü kullanmak, JSON dizelerini bir metin alanında depolamaya göre iki avantaj sağlar:

Veri doğrulama. JSON belgeleri otomatik olarak doğrulanacak ve geçersiz belgeler bir hata oluşturacaktır. Geliştirilmiş dahili depolama biçimi. JSON verileri, yapılandırılmış bir biçimde verilere hızlı okuma erişimine izin veren bir biçime dönüştürülür. Sunucu, alt nesneleri veya iç içe geçmiş değerleri anahtar veya dizine göre arayarak daha fazla esneklik ve performans sağlar.

...

NoSQL depolarının (Belge DB'leri, Anahtar-değer depoları ve Grafik DB'leri) özelleşmiş çeşitleri, özel kullanım durumları için muhtemelen daha iyi seçeneklerdir, ancak bu veri türünün eklenmesi, teknoloji yığınınızın karmaşıklığını azaltmanıza olanak sağlayabilir. Fiyat, MySQL (veya uyumlu) veritabanlarına bağlanıyor. Ancak bu, birçok kullanıcı için sorun teşkil etmez.

Önemli bir faktör olduğu için belge doğrulama ile ilgili dile dikkat edin . Sanırım iki yaklaşımın karşılaştırılması için bir dizi test yapılması gerekiyor. Bu ikisi:

  1. JSON veri türlerine sahip Mysql
  2. Mysql olmadan

Şebekede, şu andan itibaren mysql / json / performans konusunda gördüğüm kadarıyla sığ slayt paylaşımları var.

Belki gönderiniz bunun için bir merkez olabilir. Ya da belki performans sonradan düşünülmüş, emin değil ve bir grup tablo oluşturmadığınız için heyecanlısınız.


7
Bir mahkum; JSON veri türü, veri türleri, TEXT ve BLOB gibi Mysql Bellek tabloları tarafından desteklenmez. Bu, geçici bir tablo gerekliyse, bellek değil disk tabanlı bir tablo oluşturacağı anlamına gelir. Geçici bir tablonun kullanıldığı bazı durumlar burada özetlenmiştir: dev.mysql.com/doc/refman/5.7/en/internal-temporary-tables.html
raiz media

1
@raizmedia Disk tabanlı bir tablonun belleğe karşı neden bir sorun olduğunu açıklar mısınız (sanırım temelli tablo)?
lapin

@lapin Muhtemelen hız sınırlamalarından dolayı.
Little Helper

@LittleHelper, PCI 4x 40 Gb / s M.2 yuvası kullanıyorsanız ve 40 Gb / s destekli sürücü takarsanız bundan kaçınabilirsiniz. Bu hatıra kadar hızlı çalışır. Ayrıca, hafızayı biçimlendirmek için kullanılan bu sürücüye özel bir biçim de uygulayabilirsiniz.
Sergey Romanov

@SergeyRomanov, [citation required]Bu sürücüyü RAM ile kıyasladınız mı?
Bill Karwin

11

Son zamanlarda bu soruna girdim ve aşağıdaki deneyimleri özetliyorum:

1, Tüm soruları çözmenin bir yolu yok. 2, JSON'u doğru kullanmalısınız.

Bir vaka:

: Adlı bir tablom var CustomFieldve iki sütunu olmalı: name, fields. nameyerelleştirilmiş bir dizedir, içeriği şöyle olmalıdır:

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

Ve şöyle fieldsolmalı:

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

Gördüğünüz gibi, hem nameve fieldsJSON olarak kaydedilebilir ve çalışıyor!

Ancak, namebu tabloyu çok sık aramak için kullanırsam ne yapmalıyım? Kullanım JSON_CONTAINS, JSON_EXTRACT...? Açıkçası, biz bağımsız bir tabloya kaydetmek gerekir, artık JSON olarak kaydedin için iyi bir fikir değil: CustomFieldName.

Yukarıdaki durumdan, şu fikirleri aklınızda tutmanız gerektiğini düşünüyorum:

  1. MYSQL neden JSON'u destekliyor?
  2. Neden JSON kullanmak istiyorsunuz? İş mantığınız buna mı ihtiyaç duydu? Yoksa başka bir şey mi var?
  3. Asla tembel olma

Teşekkürler


2
SANAL bir sütun kullanmak ilginizi çekebilir. percona.com/blog/2016/03/07/…
Bell

10

Tecrübelerime göre, en azından MySql 5.7'de JSON uygulaması, zayıf performansı nedeniyle çok kullanışlı değil. Veri okumak ve doğrulama için o kadar da kötü değil. Bununla birlikte, JSON değişikliği, Python veya PHP ile olduğundan MySql ile 10-20 kat daha yavaştır. Çok basit bir JSON düşünelim:

{ "name": "value" }

Bunu böyle bir şeye dönüştürmemiz gerektiğini varsayalım:

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

Python veya PHP ile tüm satırları seçecek ve tek tek güncelleyecek basit bir betik oluşturabilirsiniz. Bunun için çok büyük bir işlem yapmak zorunda değilsiniz, bu nedenle diğer uygulamalar tabloyu paralel olarak kullanabilir. Elbette, isterseniz büyük bir işlem de yapabilirsiniz, bu nedenle MySql'in "tümünü veya hiçbirini" yapmayacağını garanti edersiniz, ancak diğer uygulamalar büyük olasılıkla işlem yürütme sırasında veritabanını kullanamayacaktır.

40 milyon satırlık tablom var ve Python betiği onu 3-4 saat içinde güncelliyor.

Artık MySql JSON'a sahibiz, bu yüzden artık Python veya PHP'ye ihtiyacımız yok, bunun gibi bir şey yapabiliriz:

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

Basit ve mükemmel görünüyor. Ancak hızı Python sürümünden 10-20 kat daha yavaştır ve tek işlemdir, bu nedenle diğer uygulamalar tablo verilerini paralel olarak değiştiremez.

Bu nedenle, JSON anahtarını 40 milyon satırlık tabloda sadece çoğaltmak istiyorsak, 30-40 saat boyunca tabloyu hiç kullanmamamız gerekiyor. Aklı yok.

Aracılığıyla JSON alanına benim deneyim doğrudan erişim, veri okuma Hakkında JSON_EXTRACTiçinde WHEREExtremelly yavaş (çok daha yavaş olduğunu da TEXTsahip LIKEdeğil endeksli sütun üzerinde). Sanal olarak oluşturulan sütunlar çok daha hızlı çalışır, ancak veri yapımızı önceden bilirsek JSON'a ihtiyacımız yok, bunun yerine geleneksel sütunları kullanabiliriz. JSON'u gerçekten yararlı olduğu yerlerde kullandığımızda, yani veri yapısı bilinmediğinde veya sık sık değiştiğinde (örneğin, özel eklenti ayarları), olası yeni sütunlar için düzenli olarak sanal sütun oluşturma iyi bir fikir gibi görünmüyor.

Python ve PHP JSON doğrulamasını bir cazibe gibi yapar, bu yüzden MySql tarafında JSON doğrulamasına ihtiyacımız var mı şüpheli. Neden XML, Microsoft Office belgelerini de doğrulamıyor veya yazım denetimi yapmıyorsunuz? ;)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.