การสนับสนุน Native JSON ใน MYSQL 5.7: ข้อดีข้อเสียของประเภทข้อมูล JSON ใน MYSQL คืออะไร?


114

ใน MySQL 5.7 มีการเพิ่มประเภทข้อมูลใหม่สำหรับการจัดเก็บข้อมูล JSON ในตารางMySQL เห็นได้ชัดว่าจะเป็นการเปลี่ยนแปลงที่ดีใน MySQL พวกเขาระบุประโยชน์บางอย่าง

การตรวจสอบเอกสาร - เฉพาะเอกสาร JSON ที่ถูกต้องเท่านั้นที่สามารถจัดเก็บในคอลัมน์ JSON คุณจึงได้รับการตรวจสอบความถูกต้องของข้อมูลโดยอัตโนมัติ

การเข้าถึงที่มีประสิทธิภาพ - ที่สำคัญกว่านั้นคือเมื่อคุณจัดเก็บเอกสาร JSON ในคอลัมน์ JSON เอกสารนั้นจะไม่ถูกจัดเก็บเป็นค่าข้อความธรรมดา แต่จะถูกเก็บไว้ในรูปแบบไบนารีที่ปรับให้เหมาะสมซึ่งช่วยให้สามารถเข้าถึงสมาชิกวัตถุและองค์ประกอบอาร์เรย์ได้เร็วขึ้น

ประสิทธิภาพ - ปรับปรุงประสิทธิภาพการสืบค้นของคุณโดยการสร้างดัชนีสำหรับค่าภายในคอลัมน์ JSON สามารถทำได้ด้วย“ ดัชนีการทำงาน” ในคอลัมน์เสมือน

ความสะดวก - ไวยากรณ์แบบอินไลน์เพิ่มเติมสำหรับคอลัมน์ JSON ทำให้การรวมคิวรีเอกสารภายใน SQL ของคุณเป็นเรื่องปกติมาก ตัวอย่างเช่น (features.feature คือคอลัมน์ JSON):SELECT feature->"$.properties.STREET" AS property_street FROM features WHERE id = 121254;

ว้าว ! พวกเขามีคุณสมบัติที่ยอดเยี่ยมบางอย่าง ตอนนี้จัดการข้อมูลได้ง่ายขึ้น ตอนนี้สามารถจัดเก็บข้อมูลที่ซับซ้อนมากขึ้นในคอลัมน์ได้แล้ว ดังนั้น MySQL จึงได้รับการปรุงแต่งด้วย NoSQL

ตอนนี้ฉันสามารถจินตนาการถึงข้อความค้นหาสำหรับข้อมูล JSON ได้

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

ดังนั้นฉันสามารถจัดเก็บความสัมพันธ์เล็ก ๆ น้อย ๆ ในคอลัมน์ json ได้หรือไม่? สบายดีมั้ย? มันทำลาย normalization หากเป็นไปได้แล้วผมคิดว่ามันจะทำหน้าที่เหมือน NoSQL ในคอลัมน์ ฉันต้องการทราบข้อมูลเพิ่มเติมเกี่ยวกับคุณลักษณะนี้ ข้อดีข้อเสียของประเภทข้อมูล MySQL JSON


ได้โปรดอย่าพูดในสิ่งที่ฉันคิดว่าคุณกำลังพูด นี่อ่านนี้ ของคุณเป็นอีกตัวแปรหนึ่งของความคิดที่ไม่ดี
ดึง

@Drew คุณให้คำตอบที่ยิ่งใหญ่ แต่ไม่ใช่คำถามของฉัน ฉันแค่อยากรู้ว่าถ้าเราเขียนแบบสอบถามสำหรับข้อมูล json เราอาจข้ามกฎ sql เพราะเราไม่ต้องการโต๊ะจำนวนมาก
Imran

1
คุณพูดNow it is possible to store more complex data in column. ระวัง
ดึง

2
ดัชนีการสนับสนุนประเภทข้อมูล Json และมีขนาดสมาร์ท: 64K & 4G แล้วจะเกิดปัญหาอะไรถ้าฉันต้องการจัดเก็บข้อมูล 2000 และเพิ่ม 5 ป้ายกำกับที่ซ้อนกันแทน 5 ตารางที่มีความสัมพันธ์
Imran

5
"ฉันต้องการทราบข้อมูลเพิ่มเติมเกี่ยวกับคุณลักษณะนี้" และ "ข้อดีข้อเสียของประเภทข้อมูล MySQL JSON" ไม่ใช่คำถามและหากเรียบเรียงใหม่เป็นคำถามกว้างเกินไป "ดังนั้นฉันไม่เคยคิดถึงโครงสร้างสคีมาที่ซับซ้อนและคีย์ต่างประเทศใน MySQL ฉันเก็บความสัมพันธ์ที่ซับซ้อนโดยใช้ตารางเพียงไม่กี่ตาราง" มีความขัดแย้งในตัวเองเนื่องจาก JSON ไม่ใช่ความสัมพันธ์ & FKs คำอธิบายของ "นี่คือสิ่งที่ดี" เป็นเพียงการแนะนำตัวแบบเชิงสัมพันธ์ดังนั้นอีกครั้งจึงกว้างเกินไป ทำตามตัวอย่างสร้างรายการข้อดีข้อเสียของคุณเองพร้อมข้อมูลอ้างอิงและถามว่าคุณผิดพลาดตรงไหน
philipxy

คำตอบ:


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

การใช้คอลัมน์ภายในนิพจน์หรือฟังก์ชันเช่นนี้จะทำลายโอกาสของการสืบค้นโดยใช้ดัชนีเพื่อช่วยเพิ่มประสิทธิภาพการสืบค้น แบบสอบถามที่แสดงด้านบนถูกบังคับให้ทำการสแกนตาราง

การอ้างสิทธิ์เกี่ยวกับ "การเข้าถึงที่มีประสิทธิภาพ" ทำให้เข้าใจผิด หมายความว่าหลังจากแบบสอบถามตรวจสอบแถวด้วยเอกสาร JSON แล้วจะสามารถแยกเขตข้อมูลได้โดยไม่ต้องแยกวิเคราะห์ข้อความของไวยากรณ์ JSON แต่ก็ยังต้องใช้การสแกนตารางเพื่อค้นหาแถว กล่าวอีกนัยหนึ่งแบบสอบถามต้องตรวจสอบทุกแถว

โดยการเปรียบเทียบถ้าฉันกำลังค้นหาสมุดโทรศัพท์สำหรับคนที่มีชื่อ "บิล" ฉันยังคงต้องอ่านทุกหน้าในสมุดโทรศัพท์แม้ว่าจะมีการไฮไลต์ชื่อเพื่อให้มองเห็นได้เร็วขึ้นเล็กน้อยก็ตาม

MySQL 5.7 ช่วยให้คุณกำหนดคอลัมน์เสมือนในตารางจากนั้นสร้างดัชนีบนคอลัมน์เสมือน

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

จากนั้นหากคุณสอบถามคอลัมน์เสมือนก็สามารถใช้ดัชนีและหลีกเลี่ยงการสแกนตารางได้

SELECT * FROM t1
WHERE series IN ...

นี่เป็นสิ่งที่ดี แต่มันพลาดจุดที่ใช้ JSON ส่วนที่น่าสนใจของการใช้ JSON คือช่วยให้คุณสามารถเพิ่มแอตทริบิวต์ใหม่ได้โดยไม่ต้องทำ ALTER TABLE แต่ปรากฎว่าคุณต้องกำหนดคอลัมน์พิเศษ (เสมือน) อยู่ดีหากคุณต้องการค้นหาฟิลด์ JSON ด้วยความช่วยเหลือของดัชนี

แต่คุณไม่จำเป็นต้องกำหนดคอลัมน์และดัชนีเสมือนสำหรับทุกฟิลด์ในเอกสาร JSON เฉพาะที่คุณต้องการค้นหาหรือจัดเรียงเท่านั้น อาจมีแอตทริบิวต์อื่น ๆ ใน JSON ที่คุณต้องแยกในรายการที่เลือกดังต่อไปนี้:

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

โดยทั่วไปฉันจะบอกว่านี่เป็นวิธีที่ดีที่สุดในการใช้ JSON ใน MySQL เฉพาะในรายการเลือก

เมื่อคุณอ้างอิงคอลัมน์ในส่วนคำสั่งอื่น ๆ (JOIN, WHERE, GROUP BY, HAVING, ORDER BY) การใช้คอลัมน์ทั่วไปจะมีประสิทธิภาพมากกว่าไม่ใช่ฟิลด์ภายในเอกสาร JSON

ฉันนำเสนอการพูดคุยที่เรียกว่าHow to Use JSON in MySQL Wrongในการประชุม Percona Live ในเดือนเมษายน 2018 ฉันจะอัปเดตและพูดคุยซ้ำที่ Oracle Code One ในฤดูใบไม้ร่วง

มีปัญหาอื่น ๆ เกี่ยวกับ JSON ตัวอย่างเช่นในการทดสอบของฉันต้องการพื้นที่จัดเก็บเอกสาร JSON มากถึง 2-3 เท่าเมื่อเทียบกับคอลัมน์ทั่วไปที่จัดเก็บข้อมูลเดียวกัน

MySQL กำลังส่งเสริมความสามารถ JSON ใหม่ของพวกเขาในเชิงรุกโดยส่วนใหญ่เพื่อห้ามปรามผู้คนจากการย้ายไปยัง MongoDB แต่การจัดเก็บข้อมูลที่เน้นเอกสารเช่น MongoDB นั้นโดยพื้นฐานแล้วเป็นวิธีการจัดระเบียบข้อมูลที่ไม่เกี่ยวข้อง มันแตกต่างจากเชิงสัมพันธ์ ฉันไม่ได้บอกว่าอย่างใดอย่างหนึ่งดีกว่าอีกวิธีหนึ่งมันเป็นเพียงเทคนิคที่แตกต่างกันซึ่งเหมาะกับแบบสอบถามประเภทต่างๆ

คุณควรเลือกใช้ JSON เมื่อ JSON ทำให้การสืบค้นของคุณมีประสิทธิภาพมากขึ้น

อย่าเลือกเทคโนโลยีเพียงเพราะมันใหม่หรือเพื่อแฟชั่น


แก้ไข: การใช้งานคอลัมน์เสมือนใน MySQL ควรใช้ดัชนีหากส่วนคำสั่ง WHERE ของคุณใช้นิพจน์เดียวกันกับคำจำกัดความของคอลัมน์เสมือน นั่นคือสิ่งต่อไปนี้ควรใช้ดัชนีบนคอลัมน์เสมือนเนื่องจากมีการกำหนดคอลัมน์เสมือนAS (JSON_EXTRACT(data,"$.series"))

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

ยกเว้นฉันพบโดยการทดสอบคุณสมบัตินี้ว่ามันไม่ทำงานด้วยเหตุผลบางประการหากนิพจน์เป็นฟังก์ชันการแยก JSON ใช้งานได้กับนิพจน์ประเภทอื่น ๆ ไม่ใช่ฟังก์ชัน JSON


7
ตามลิงค์ไปยังสไลด์
Paul Campbell

ข้อดีคือเทคโนโลยีทั้ง 2 อย่างมีประโยชน์ในตัวเองหมายความว่าเราตัดสินใจได้ว่าสิ่งใดจะเหมาะกับความต้องการของเราและสิ่งที่ทำให้เราได้เปรียบมากขึ้นในด้านความปลอดภัยและประสิทธิภาพ
Christopher Pelayo

1
ปมของปัญหาคือยังคงต้องมีการปรับเปลี่ยนตารางเพื่อใช้ประโยชน์จากดัชนีในคอลัมน์ที่สร้างขึ้นสำหรับทุกคีย์ใหม่ใน JSON ดีใจที่ได้เห็นมันถูกชี้ให้เห็น
user1454926

เฉพาะในกรณีที่คุณต้องการเพิ่มคอลัมน์เสมือนและ / หรือดัชนี หากคุณถือว่าข้อมูล JSON เป็น "กล่องดำ" และไม่พยายามทำคำค้นหาใด ๆ ที่ค้นหาหรือจัดเรียงในช่องย่อยภายใน JSON คุณก็ไม่จำเป็นต้องทำเช่นนั้น นั่นเป็นเหตุผลที่ผมขอแนะนำเพื่อหลีกเลี่ยงการอ้างอิง JSON ในJOIN, WHEREหรือคำสั่งอื่น ๆ เพียงดึงคอลัมน์ JSON ในรายการที่เลือก
Bill Karwin

ลิงก์ไปยังสไลด์เสีย @BillKarwin
lakesare

43

ต่อไปนี้จากMySQL 5.7 นำความเซ็กซี่กลับมาด้วย JSONฟังดูดีสำหรับฉัน:

การใช้ JSON Data Type ใน MySQL มาพร้อมกับข้อดีสองประการในการจัดเก็บสตริง JSON ในช่องข้อความ:

การตรวจสอบข้อมูล. เอกสาร JSON จะได้รับการตรวจสอบโดยอัตโนมัติและเอกสารที่ไม่ถูกต้องจะทำให้เกิดข้อผิดพลาด ปรับปรุงรูปแบบการจัดเก็บข้อมูลภายใน ข้อมูล JSON จะถูกแปลงเป็นรูปแบบที่ช่วยให้สามารถอ่านข้อมูลได้อย่างรวดเร็วในรูปแบบที่มีโครงสร้าง เซิร์ฟเวอร์สามารถค้นหาวัตถุย่อยหรือค่าที่ซ้อนกันตามคีย์หรือดัชนีทำให้เพิ่มความยืดหยุ่นและประสิทธิภาพ

...

รสชาติเฉพาะของร้านค้า NoSQL (ฐานข้อมูลเอกสารที่เก็บคีย์ - ค่าและฐานข้อมูลกราฟ) อาจเป็นตัวเลือกที่ดีกว่าสำหรับกรณีการใช้งานเฉพาะของพวกเขา แต่การเพิ่มประเภทข้อมูลนี้อาจช่วยให้คุณลดความซับซ้อนของกองเทคโนโลยีของคุณได้ ราคานี้เชื่อมต่อกับฐานข้อมูล MySQL (หรือเข้ากันได้) แต่นั่นไม่ใช่ปัญหาสำหรับผู้ใช้จำนวนมาก

สังเกตภาษาเกี่ยวกับการตรวจสอบความถูกต้องของเอกสารเนื่องจากเป็นปัจจัยสำคัญ ฉันเดาว่าต้องทำการทดสอบแบตเตอรี่เพื่อเปรียบเทียบทั้งสองวิธี ทั้งสองเป็น:

  1. Mysql ที่มีประเภทข้อมูล JSON
  2. Mysql ไม่มี

เน็ตมี แต่สไลด์แชร์ตื้น ๆ ณ ตอนนี้ในหัวข้อ mysql / json / ประสิทธิภาพจากสิ่งที่ฉันเห็น

บางทีโพสต์ของคุณอาจเป็นศูนย์กลางได้ หรือบางทีประสิทธิภาพอาจเป็นความคิดไม่แน่ใจและคุณแค่รู้สึกตื่นเต้นที่จะไม่สร้างตารางมากมาย


7
หนึ่งคอน; ตารางหน่วยความจำ Mysql ไม่รองรับชนิดข้อมูล JSON เช่นชนิดข้อมูล TEXT & BLOB ซึ่งหมายความว่าหากจำเป็นต้องใช้ตารางชั่วคราวก็จะสร้างตารางที่ใช้ดิสก์ไม่ใช่หน่วยความจำ บางกรณีเมื่อใช้ตารางชั่วคราวที่ระบุไว้ที่นี่: dev.mysql.com/doc/refman/5.7/en/internal-tem สร้างสรรค์-tables.html
raiz media

1
@raizmedia คุณช่วยอธิบายให้ละเอียดได้ไหมว่าเหตุใดตารางที่ใช้ดิสก์จึงเป็นปัญหาเทียบกับหน่วยความจำ (ฉันเดาตามตาราง)
lapin

@lapin อาจเป็นเพราะข้อ จำกัด ด้านความเร็ว
Little Helper

@LittleHelper คุณสามารถหลีกเลี่ยงได้หากคุณใช้สล็อต PCI 4x 40 Gb / s M.2 และใส่ไดรฟ์ที่รองรับ 40 Gb / s ซึ่งทำงานได้เร็วพอ ๆ กับ memmory คุณสามารถใช้รูปแบบพิเศษกับไดรฟ์ที่ใช้ในการจัดรูปแบบ memmory ได้
Sergey Romanov

@SergeyRomanov [citation required]คุณเปรียบเทียบไดรฟ์เทียบกับ RAM แล้วหรือยัง?
Bill Karwin

11

เมื่อเร็ว ๆ นี้ฉันประสบปัญหานี้และฉันสรุปประสบการณ์ต่อไปนี้:

1 ไม่มีวิธีแก้ปัญหาทั้งหมด 2 คุณควรใช้ JSON อย่างถูกต้อง

หนึ่งกรณี:

ฉันมีตารางชื่อ: CustomFieldและต้องมีสองคอลัมน์: name, fields. nameเป็นสตริงที่แปลเป็นภาษาท้องถิ่นเนื้อหาควรชอบ:

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

และfieldsควรเป็นดังนี้:

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

ที่คุณสามารถดูทั้งnameและfieldsสามารถบันทึกเป็น JSON และการทำงาน!

อย่างไรก็ตามหากฉันใช้nameเพื่อค้นหาตารางนี้บ่อยมากฉันควรทำอย่างไร? ใช้JSON_CONTAINS, JSON_EXTRACT... ? เห็นได้ชัดว่ามันไม่ได้เป็นความคิดที่ดีที่จะบันทึกเป็น JSON CustomFieldNameอีกต่อไปเราควรจะบันทึกลงในตารางอิสระ

จากกรณีข้างต้นฉันคิดว่าคุณควรคำนึงถึงแนวคิดเหล่านี้:

  1. ทำไม MYSQL จึงรองรับ JSON
  2. ทำไมคุณถึงต้องการใช้ JSON ตรรกะทางธุรกิจของคุณต้องการสิ่งนี้หรือไม่? หรือมีอย่างอื่น?
  3. อย่าขี้เกียจ

ขอบคุณ


2
คุณอาจสนใจใช้คอลัมน์ VIRTUAL percona.com/blog/2016/03/07/…
เบลล์

10

จากประสบการณ์ของฉันการใช้งาน JSON อย่างน้อยใน MySql 5.7 นั้นไม่มีประโยชน์มากนักเนื่องจากประสิทธิภาพไม่ดี การอ่านข้อมูลและการตรวจสอบความถูกต้องก็ไม่เลวร้ายนัก อย่างไรก็ตามการแก้ไข JSON จะช้าลง 10-20 เท่าเมื่อใช้ MySql ที่ใช้ Python หรือ PHP ลองนึกภาพ JSON ที่เรียบง่ายมาก:

{ "name": "value" }

สมมติว่าเราต้องแปลงให้เป็นแบบนั้น:

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

คุณสามารถสร้างสคริปต์ง่ายๆด้วย Python หรือ PHP ซึ่งจะเลือกแถวทั้งหมดและอัปเดตทีละแถว คุณไม่ได้ถูกบังคับให้ทำธุรกรรมขนาดใหญ่เพียงรายการเดียวดังนั้นแอปพลิเคชันอื่น ๆ จะสามารถใช้ตารางควบคู่กันได้ แน่นอนว่าคุณสามารถทำธุรกรรมขนาดใหญ่ได้หากต้องการดังนั้นคุณจะได้รับการรับประกันว่า MySql จะดำเนินการ "ทั้งหมดหรือไม่มีเลย" แต่แอปพลิเคชันอื่น ๆ ส่วนใหญ่อาจไม่สามารถใช้ฐานข้อมูลในระหว่างการทำธุรกรรมได้

ฉันมีตาราง 40 ล้านแถวและสคริปต์ Python จะอัปเดตใน 3-4 ชั่วโมง

ตอนนี้เรามี MySql JSON แล้วดังนั้นเราจึงไม่จำเป็นต้องใช้ Python หรือ PHP อีกต่อไปเราสามารถทำสิ่งนั้นได้:

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

มันดูเรียบง่ายและยอดเยี่ยม อย่างไรก็ตามความเร็วของมันช้ากว่าเวอร์ชัน Python 10-20 เท่าและเป็นธุรกรรมเดียวดังนั้นแอปพลิเคชันอื่น ๆ จึงไม่สามารถแก้ไขข้อมูลตารางแบบขนานได้

ดังนั้นหากเราต้องการทำซ้ำคีย์ JSON ในตาราง 40 ล้านแถวเราไม่จำเป็นต้องใช้ตารางเลยในช่วง 30-40 ชั่วโมง มันไม่มีเหตุผล

เกี่ยวกับการอ่านข้อมูลจากการเข้าถึงโดยตรงของฉันประสบการณ์ในสนาม JSON ผ่านJSON_EXTRACTในWHEREนี้ยังช้า Extremelly (ช้ามากที่TEXTมีLIKEในคอลัมน์ไม่ได้จัดทำดัชนี) คอลัมน์ที่สร้างขึ้นเสมือนทำงานได้เร็วกว่ามากอย่างไรก็ตามหากเราทราบโครงสร้างข้อมูลของเราล่วงหน้าเราไม่จำเป็นต้องใช้ JSON เราสามารถใช้คอลัมน์แบบเดิมแทนได้ เมื่อเราใช้ JSON ในที่ที่มีประโยชน์จริงๆกล่าวคือเมื่อไม่รู้จักโครงสร้างข้อมูลหรือมีการเปลี่ยนแปลงบ่อยครั้ง (เช่นการตั้งค่าปลั๊กอินที่กำหนดเอง) การสร้างคอลัมน์เสมือนเป็นประจำสำหรับคอลัมน์ใหม่ที่เป็นไปได้ดูเหมือนจะไม่เป็นความคิดที่ดี

Python และ PHP ทำให้การตรวจสอบความถูกต้องของ JSON เป็นเสน่ห์ดังนั้นจึงเป็นเรื่องที่น่าสงสัยว่าเราต้องการการตรวจสอบความถูกต้องของ JSON ในด้าน MySql หรือไม่ ทำไมไม่ตรวจสอบความถูกต้องของเอกสาร XML, Microsoft Office หรือตรวจการสะกดคำด้วย? ;)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.