Hỗ trợ JSON gốc trong MYSQL 5.7: Ưu và nhược điểm của kiểu dữ liệu JSON trong MYSQL là gì?


113

Trong MySQL 5.7, một kiểu dữ liệu mới để lưu trữ dữ liệu JSON trong các bảng MySQL đã được thêm vào. Nó rõ ràng sẽ là một thay đổi lớn trong MySQL. Họ liệt kê một số lợi ích

Xác thực tài liệu - Chỉ các tài liệu JSON hợp lệ mới có thể được lưu trữ trong cột JSON, vì vậy, bạn có thể tự động xác thực dữ liệu của mình.

Truy cập hiệu quả - Quan trọng hơn, khi bạn lưu trữ tài liệu JSON trong cột JSON, nó không được lưu trữ dưới dạng giá trị văn bản thuần túy. Thay vào đó, nó được lưu trữ ở định dạng nhị phân tối ưu hóa cho phép truy cập nhanh hơn vào các thành viên đối tượng và các phần tử mảng.

Hiệu suất - Cải thiện hiệu suất truy vấn của bạn bằng cách tạo chỉ mục trên các giá trị trong các cột JSON. Điều này có thể đạt được với "chỉ mục chức năng" trên các cột ảo.

Thuận tiện - Cú pháp nội tuyến bổ sung cho các cột JSON làm cho việc tích hợp các truy vấn Tài liệu trong SQL của bạn trở nên rất tự nhiên. Ví dụ: features.feature là một cột JSON):SELECT feature->"$.properties.STREET" AS property_street FROM features WHERE id = 121254;

WOW! chúng bao gồm một số tính năng tuyệt vời. Bây giờ nó dễ dàng hơn để thao tác dữ liệu. Bây giờ có thể lưu trữ nhiều dữ liệu phức tạp hơn trong cột. Vì vậy, MySQL bây giờ có hương vị với NoSQL.

Bây giờ tôi có thể hình dung một truy vấn cho dữ liệu JSON giống như

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

Vì vậy, tôi có thể lưu trữ các quan hệ nhỏ rất lớn trong vài json colum không? Liệu nó có tốt không? Nó có phá vỡ bình thường hóa không. Nếu điều này là có thể thì tôi đoán nó sẽ hoạt động giống như NoSQL trong một cột MySQL . Tôi thực sự muốn biết thêm về tính năng này. Ưu nhược điểm của kiểu dữ liệu MySQL JSON.


ồ xin đừng nói những gì tôi nghĩ bạn đang nói. Đây, hãy đọc cái này . Của bạn là một biến thể khác trên một ý tưởng tồi.
Drew

@Drew Bạn đã đưa ra một câu trả lời lớn. Nhưng nó không phải là câu hỏi của tôi. Tôi chỉ muốn biết rằng nếu chúng ta viết một truy vấn cho dữ liệu json thì chúng ta có thể bỏ qua các quy tắc sql. vì chúng tôi không cần nhiều bàn
Imran

1
bạn nói Now it is possible to store more complex data in column. Hãy cẩn thận
Drew

2
Chỉ số hỗ trợ kiểu dữ liệu Json và Nó có kích thước thông minh: 64K & 4G. Vì vậy, vấn đề là gì nếu tôi muốn lưu trữ 2000 dữ liệu và thêm 5 nhãn lồng nhau thay vì 5 bảng có quan hệ?
Imran

5
"Tôi thực sự muốn biết thêm về tính năng này." và "Ưu và nhược điểm của kiểu dữ liệu MySQL JSON." không phải là câu hỏi và nếu được diễn đạt lại là câu hỏi quá rộng. "Vì vậy, tôi không bao giờ nghĩ đến một cấu trúc lược đồ phức tạp và các khóa ngoại trong MySQL. Tôi lưu trữ các quan hệ phức tạp chỉ bằng một vài bảng." tự mâu thuẫn vì JSON không phải là quan hệ & FK. Giải thích về "điều này có tốt không" chỉ là phần giới thiệu về mô hình quan hệ, vì vậy một lần nữa điều này quá rộng. Làm việc qua một số ví dụ, lập danh sách ưu và nhược điểm của riêng bạn với tài liệu tham khảo và hỏi xem bạn đã sai ở đâu.
philipxy

Câu trả lời:


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

Việc sử dụng một cột bên trong một biểu thức hoặc hàm như thế này làm hỏng bất kỳ cơ hội nào của truy vấn bằng cách sử dụng chỉ mục để giúp tối ưu hóa truy vấn. Truy vấn hiển thị ở trên buộc phải thực hiện quét bảng.

Tuyên bố về "truy cập hiệu quả" là gây hiểu lầm. Có nghĩa là sau khi truy vấn kiểm tra một hàng với tài liệu JSON, nó có thể trích xuất một trường mà không cần phải phân tích cú pháp văn bản của cú pháp JSON. Nhưng nó vẫn cần quét bảng để tìm kiếm các hàng. Nói cách khác, truy vấn phải kiểm tra mọi hàng.

Tương tự như vậy, nếu tôi đang tìm kiếm những người có tên "Bill" trong danh bạ điện thoại, tôi vẫn phải đọc từng trang trong danh bạ, ngay cả khi những cái tên đầu tiên đã được đánh dấu để giúp phát hiện họ nhanh hơn một chút.

MySQL 5.7 cho phép bạn xác định một cột ảo trong bảng, sau đó tạo một chỉ mục trên cột ảo.

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

Sau đó, nếu bạn truy vấn cột ảo, nó có thể sử dụng chỉ mục và tránh quét bảng.

SELECT * FROM t1
WHERE series IN ...

Điều này thật hay, nhưng hơi thiếu sót khi sử dụng JSON. Phần hấp dẫn của việc sử dụng JSON là nó cho phép bạn thêm các thuộc tính mới mà không cần phải thực hiện ALTER TABLE. Nhưng hóa ra bạn phải xác định thêm một cột (ảo), nếu bạn muốn tìm kiếm các trường JSON với sự trợ giúp của chỉ mục.

Nhưng bạn không phải xác định các cột và chỉ mục ảo cho mọi trường trong tài liệu JSON — chỉ những trường bạn muốn tìm kiếm hoặc sắp xếp. Có thể có các thuộc tính khác trong JSON mà bạn chỉ cần trích xuất trong danh sách chọn như sau:

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

Tôi thường nói rằng đây là cách tốt nhất để sử dụng JSON trong MySQL. Chỉ trong danh sách lựa chọn.

Khi bạn tham chiếu các cột trong các mệnh đề khác (THAM GIA, WHERE, GROUP BY, HAVING, ORDER BY), sẽ hiệu quả hơn nếu sử dụng các cột thông thường, không phải các trường trong tài liệu JSON.

Tôi đã trình bày một bài nói chuyện có tên Cách sử dụng JSON trong MySQL Sai tại hội nghị Percona Live vào tháng 4 năm 2018. Tôi sẽ cập nhật và lặp lại bài nói chuyện tại Oracle Code One vào mùa thu.

Có các vấn đề khác với JSON. Ví dụ: trong các thử nghiệm của tôi, nó yêu cầu dung lượng lưu trữ cho tài liệu JSON gấp 2-3 lần so với các cột thông thường lưu trữ cùng một dữ liệu.

MySQL đang quảng bá mạnh mẽ các khả năng JSON mới của họ, phần lớn là để khuyên mọi người không chuyển sang MongoDB. Nhưng lưu trữ dữ liệu hướng tài liệu như MongoDB về cơ bản là một cách tổ chức dữ liệu không quan hệ. Nó khác với quan hệ. Tôi không nói cái này tốt hơn cái kia, nó chỉ là một kỹ thuật khác, phù hợp với các loại truy vấn khác nhau.

Bạn nên chọn sử dụng JSON khi JSON làm cho các truy vấn của bạn hiệu quả hơn.

Đừng chọn một công nghệ chỉ vì nó mới hoặc vì mục đích thời trang.


Chỉnh sửa: Việc triển khai cột ảo trong MySQL được cho là sử dụng chỉ mục nếu mệnh đề WHERE của bạn sử dụng chính xác biểu thức giống như định nghĩa của cột ảo. Đó là, phần sau sẽ sử dụng chỉ mục trên cột ảo, vì cột ảo được xác địnhAS (JSON_EXTRACT(data,"$.series"))

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

Ngoại trừ tôi đã phát hiện ra bằng cách kiểm tra tính năng này rằng nó KHÔNG hoạt động vì một số lý do nếu biểu thức là một hàm trích xuất JSON. Nó hoạt động với các loại biểu thức khác, không chỉ các hàm JSON.


7
Rất đáng để theo liên kết đến các trang trình bày
Paul Campbell

Điểm tốt là cả 2 công nghệ đều tốt theo nghĩa riêng của chúng, chúng tôi quyết định cái nào sẽ phù hợp với nhu cầu của chúng tôi và cái nào mang lại cho chúng tôi lợi thế hơn về bảo mật và hiệu suất.
Christopher Pelayo

1
Điểm mấu chốt của vấn đề là ALTER TABLE vẫn cần thiết để sử dụng chỉ mục trên cột được tạo cho mọi khóa mới trong JSON. Rất vui khi thấy nó được chỉ ra.
user1454926

Chỉ khi bạn cần thêm một cột ảo và / hoặc một chỉ mục. Nếu bạn coi dữ liệu JSON như một "hộp đen" và không cố gắng thực hiện bất kỳ truy vấn nào tìm kiếm hoặc sắp xếp trên các trường phụ trong JSON, thì bạn không cần phải làm điều đó. Đó là lý do tôi khuyên bạn nên tham khảo để tránh JSON trong JOIN, WHEREhoặc điều khoản khác. Chỉ cần tìm nạp cột JSON trong danh sách chọn.
Bill Karwin

Liên kết đến các trang trình bày bị hỏng, @BillKarwin.
Lakeare

43

Những điều sau đây từ MySQL 5.7 mang lại sự gợi cảm với JSON nghe có vẻ tốt với tôi:

Sử dụng Kiểu dữ liệu JSON trong MySQL có hai lợi thế so với việc lưu trữ chuỗi JSON trong trường văn bản:

Xác nhận dữ liệu. Các tài liệu JSON sẽ được xác thực tự động và các tài liệu không hợp lệ sẽ tạo ra lỗi. Cải thiện định dạng bộ nhớ trong. Dữ liệu JSON được chuyển đổi sang định dạng cho phép đọc nhanh dữ liệu ở định dạng có cấu trúc. Máy chủ có thể tra cứu các subobject hoặc các giá trị lồng nhau theo khóa hoặc chỉ mục, cho phép tăng tính linh hoạt và hiệu suất.

...

Các hương vị chuyên biệt của cửa hàng NoSQL (Cơ sở dữ liệu tài liệu, Kho lưu trữ khóa-giá trị và Cơ sở dữ liệu đồ thị) có thể là lựa chọn tốt hơn cho các trường hợp sử dụng cụ thể của chúng, nhưng việc bổ sung loại dữ liệu này có thể cho phép bạn giảm độ phức tạp của ngăn xếp công nghệ của mình. Giá cả phù hợp với cơ sở dữ liệu MySQL (hoặc tương thích). Nhưng đó là một vấn đề không đối với nhiều người dùng.

Lưu ý ngôn ngữ về xác thực tài liệu vì nó là một yếu tố quan trọng. Tôi đoán rằng cần phải thực hiện một loạt các bài kiểm tra để so sánh hai cách tiếp cận. Hai bản thể đó:

  1. Mysql với kiểu dữ liệu JSON
  2. Mysql không có

Hiện tại, mạng có nhưng các slideshares nông về chủ đề mysql / json / performance từ những gì tôi đang thấy.

Có lẽ bài đăng của bạn có thể là một trung tâm cho nó. Hoặc có lẽ hiệu suất là một suy nghĩ sau, không chắc chắn, và bạn chỉ vui mừng khi không tạo ra một loạt các bảng.


7
Một con; Kiểu dữ liệu JSON không được hỗ trợ bởi các bảng Mysql Memory, như kiểu dữ liệu, TEXT & BLOB. Điều này có nghĩa là nếu một bảng tạm thời được yêu cầu, nó sẽ tạo một bảng dựa trên đĩa chứ không phải bộ nhớ. Một số trường hợp khi sử dụng bảng tạm thời được nêu ở đây: dev.mysql.com/doc/refman/5.7/en/internal-temporary-tables.html
raiz media

1
@raizmedia Bạn có thể vui lòng giải thích tại sao một bảng dựa trên đĩa là một vấn đề so với bộ nhớ (tôi đoán dựa trên bảng)?
lapin

@lapin Có thể do giới hạn tốc độ.
Little Helper,

@LittleHelper bạn có thể tránh nó nếu bạn sử dụng khe cắm PCI 4x 40 Gb / s M.2 và lắp ổ đĩa được hỗ trợ 40 Gb / s. Điều này hoạt động nhanh như ghi nhớ. Bạn có thể áp dụng một định dạng đặc biệt cho ổ đĩa đó được sử dụng để định dạng bộ nhớ.
Sergey Romanov

@SergeyRomanov, [citation required]Bạn đã chuẩn ổ đĩa đó so với RAM chưa?
Bill Karwin

11

Gần đây tôi gặp phải vấn đề này và tôi đúc kết lại những kinh nghiệm sau:

1, Không có cách nào để giải quyết tất cả các câu hỏi. 2, Bạn nên sử dụng JSON đúng cách.

Một trường hợp:

Tôi có một bảng tên:, CustomFieldvà nó phải có hai cột: name, fields. namelà một chuỗi được bản địa hóa, nó có nội dung như sau:

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

fieldssẽ như thế này:

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

Như bạn thấy, cả cái namevà cái fieldsđều có thể được lưu dưới dạng JSON, và nó hoạt động!

Tuy nhiên, nếu tôi sử dụng nameđể tìm kiếm bảng này rất thường xuyên, tôi phải làm gì? Sử dụng JSON_CONTAINS, JSON_EXTRACT...? Rõ ràng, nó không phải là một ý tưởng tốt để lưu nó dưới dạng JSON nữa, chúng ta nên lưu nó vào một bảng độc lập: CustomFieldName.

Từ trường hợp trên, tôi nghĩ bạn nên ghi nhớ những ý tưởng sau:

  1. Tại sao MYSQL hỗ trợ JSON?
  2. Tại sao bạn muốn sử dụng JSON? Logic kinh doanh của bạn có cần điều này không? Hay có cái gì khác?
  3. Đừng bao giờ lười biếng

Cảm ơn


2
Bạn có thể quan tâm đến việc sử dụng cột VIRTUAL. percona.com/blog/2016/03/07/…
Bell

10

Theo kinh nghiệm của tôi, việc triển khai JSON ít nhất trong MySql 5.7 không hữu ích lắm do hiệu suất kém. Chà, nó không quá tệ để đọc dữ liệu và xác nhận. Tuy nhiên, sửa đổi JSON với MySql chậm hơn 10-20 lần với Python hoặc PHP. Hãy tưởng tượng JSON rất đơn giản:

{ "name": "value" }

Giả sử chúng ta phải chuyển đổi nó thành một cái gì đó như thế:

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

Bạn có thể tạo tập lệnh đơn giản bằng Python hoặc PHP sẽ chọn tất cả các hàng và cập nhật từng hàng một. Bạn không bị buộc phải thực hiện một giao dịch lớn cho nó, vì vậy các ứng dụng khác sẽ có thể sử dụng bảng song song. Tất nhiên, bạn cũng có thể thực hiện một giao dịch lớn nếu muốn, vì vậy bạn sẽ được đảm bảo rằng MySql sẽ thực hiện "tất cả hoặc không có gì", nhưng các ứng dụng khác có thể sẽ không thể sử dụng cơ sở dữ liệu trong quá trình thực hiện giao dịch.

Tôi có bảng 40 triệu hàng và tập lệnh Python cập nhật nó trong 3-4 giờ.

Bây giờ chúng ta có MySql JSON, vì vậy chúng ta không cần Python hoặc PHP nữa, chúng ta có thể làm điều gì đó như sau:

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

Nó trông đơn giản và tuyệt vời. Tuy nhiên, tốc độ của nó chậm hơn 10-20 lần so với phiên bản Python và nó là một giao dịch đơn lẻ, vì vậy các ứng dụng khác không thể sửa đổi dữ liệu bảng song song.

Vì vậy, nếu chúng ta chỉ muốn sao chép khóa JSON trong bảng 40 triệu hàng, chúng ta cần hoàn toàn không sử dụng bảng trong vòng 30-40 giờ. Nó không có ý nghĩa.

Về việc đọc dữ liệu, theo kinh nghiệm của tôi, việc truy cập trực tiếp vào trường JSON thông qua JSON_EXTRACTin WHEREcũng cực kỳ chậm (chậm hơn nhiều so TEXTvớiLIKE trên cột không được lập chỉ mục). Các cột được tạo ảo hoạt động nhanh hơn nhiều, tuy nhiên, nếu chúng ta biết trước cấu trúc dữ liệu của mình, chúng ta không cần JSON, thay vào đó chúng ta có thể sử dụng các cột truyền thống. Khi chúng tôi sử dụng JSON ở nơi nó thực sự hữu ích, tức là khi cấu trúc dữ liệu không xác định hoặc thay đổi thường xuyên (ví dụ: cài đặt plugin tùy chỉnh), việc tạo cột ảo thường xuyên cho bất kỳ cột mới nào có thể không phải là ý kiến ​​hay.

Python và PHP làm cho việc xác thực JSON giống như một sự quyến rũ, vì vậy có vấn đề là chúng ta có cần xác thực JSON ở phía MySql hay không. Tại sao cũng không xác thực tài liệu XML, Microsoft Office hoặc kiểm tra chính tả? ;)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.