RE:NODE

ბაზები12 წუთის საკითხავი

MySQL-ის JSON სვეტები: ფუნქციები, index-ები და generated სვეტები

როგორ ინახავს მონაცემებს MySQL-ის JSON ტიპი, რომელი ფუნქციები და ოპერატორები ღირს ცოდნად და როგორ დააინდექსო JSON ველები generated სვეტებითა და multi-valued index-ებით.

0 მკითხველი

MySQL-ს ნამდვილი JSON ტიპი 5.7-დან აქვს, და 8.4-ში ის სავსებით კარგი ადგილია მონაცემებისთვის, რომელთა ფორმა იცვლება: პროდუქტის ატრიბუტები, პარამეტრების ბლოკები, webhook-ის payload-ები, feature flag-ები. რაც ის არ არის - სქემის დიზაინისგან გათავისუფლება. JSON სვეტის პირდაპირ დაინდექსება შეუძლებელია, query, რომელიც მის შიგნით ველზე ფილტრავს, მთელ ცხრილს scan-ავს, და ყოველი მნიშვნელობა ბრუნდება ტიპით, რომელზეც უნდა იფიქრო. სამივეზე პასუხი ერთი და იგივე შესაძლებლობაა: generated სვეტი, რომელიც დოკუმენტიდან ერთ ველს იღებს, მასზე ჩვეულებრივი index-ით. ეს კომბინაცია - მოქნილი დოკუმენტი და დაინდექსებული ველები, რომლებზეც რეალურად აკეთებ query-ს - არის ის, როგორ გამოიყენო JSON MySQL-ში ისე, რომ არ ინანო.

რას ინახავს სინამდვილეში JSON ტიპი#

JSON სვეტი ტექსტი არ არის მიმაგრებული შემოწმებით. insert-ისას MySQL დოკუმენტს არჩევს, უარყოფს, თუ არავალიდურია, და ინახავს ბინარულ ფორმატში, რომელიც ერთი წევრის წაკითხვის საშუალებას იძლევა მთლიანის გარჩევის გარეშე.

sql
CREATE TABLE products (  id         BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,  sku        VARCHAR(40) NOT NULL UNIQUE,  attributes JSON NOT NULL DEFAULT (JSON_OBJECT()),  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP);INSERT INTO products (sku, attributes) VALUES  ('MUG-01', '{"colour": "blue", "capacity_ml": 350, "tags": ["kitchen", "gift"]}'),  ('TEE-02', '{"colour": "black", "sizes": ["S", "M", "L"], "price": 19.5}');

გარჩეულად შენახვის ზოგიერთი შედეგი:

  • არავალიდური JSON შეცდომაა და არა გაფრთხილება. INSERT ... VALUES ('{colour: blue}') ვარდება შეცდომით 3140, Invalid JSON text. ეს უპირატესობაა: TEXT სვეტი ამ ნაგავს შეინახავდა.
  • დოკუმენტი ნორმალიზდება. whitespace იშლება, ობიექტის გასაღებები ლაგდება, და თუ გასაღები ორჯერ გვხვდება, ბოლო მნიშვნელობა იმარჯვებს. თავდაპირველ ტექსტს ბაიტ-ბაიტ ვეღარ დაიბრუნებ, რაც მნიშვნელოვანია, თუ ხელმოწერილ payload-ებს ინახავ - ისინი TEXT ან BLOB სვეტში შეინახე.
  • ზომას `max_allowed_packet` ზღუდავს, 8.4-ში ნაგულისხმევად 64 MB. პრაქტიკაში რამდენიმე ასეულ კილობაიტზე დიდი დოკუმენტები დიზაინის პრობლემაა ამ ზღვრამდე მისვლამდე დიდი ხნით ადრე.
  • JSON სვეტს ლიტერალური ნაგულისხმევი მნიშვნელობა ვერ ექნება. გამოსახულებით ნაგულისხმევი DEFAULT (JSON_OBJECT()) ზემოთ მოცემულ მაგალითში, თავისი ფრჩხილებით, 8.0.13-დან დაშვებულია.

JSON_STORAGE_SIZE(attributes) გეუბნება, რამდენ ბაიტს იკავებს მნიშვნელობა დისკზე, რაც სწრაფი გზაა იმ ხაზების საპოვნელად, რომლებშიც ვიღაც ყველაფერს ტენიდა.

მნიშვნელობების წაკითხვა: path-ები, -> და ->>#

ველებს path გამოსახულებით მიმართავ. $ მთელი დოკუმენტია, $.colour - წევრი, $.tags[0] - მასივის ელემენტი, $.tags[last] - ბოლო, $.tags[*] - ყველა ელემენტი, ხოლო $**.price - ნებისმიერი price ნებისმიერ სიღრმეზე. წევრის სახელი, რომელშიც ჰარი ან ტირეა, ბრჭყალებში იწერება: $."list-price".

წაკითხვის უმეტესობას ორი ოპერატორი ფარავს:

გამოსახულებაეკვივალენტიაბრუნებს
attributes->'$.colour'JSON_EXTRACT(attributes, '$.colour')JSON: "blue", ბრჭყალებით
attributes->>'$.colour'JSON_UNQUOTE(JSON_EXTRACT(...))ტექსტი: blue
JSON_CONTAINS_PATH(attributes, 'one', '$.price')-1, თუ path არსებობს
JSON_TYPE(attributes->'$.price')-DOUBLE, INTEGER, STRING, ARRAY...
sql
SELECT sku,       attributes->>'$.colour'      AS colour,       attributes->'$.capacity_ml'  AS capacity,       JSON_LENGTH(attributes, '$.tags') AS tag_countFROM productsWHERE attributes->>'$.colour' = 'blue';

რომელი ოპერატორი გამოიყენო, გემოვნების საკითხი არ არის. -> JSON მნიშვნელობას აბრუნებს, ამიტომ JSON-ად ადარებს: რიცხვებს რიცხვებად, სტრიქონებს სტრიქონებად. ->> ტექსტს აბრუნებს, ამიტომ attributes->>'$.price' > 9 სტრიქონებს ადარებს, თუ MySQL არ გარდაქმნის, ხოლო ტექსტად '10' < '9'. ->> გამოიყენე სტრიქონებისთვის, რომლებსაც აჩვენებ ან სტრიქონს ადარებ; რიცხვებისთვის გამოიყენე -> (ან ცხადი CAST).

ძებნა მასივებსა და ობიექტებში#

მასივში წევრობით ფილტრაცია ის ადგილია, სადაც JSON თავის ადგილს იმსახურებს, რადგან ალტერნატივა join ცხრილია.

sql
-- Products tagged 'gift'SELECT sku FROM products WHERE 'gift' MEMBER OF (attributes->'$.tags');-- Contains all of these valuesSELECT sku FROM productsWHERE JSON_CONTAINS(attributes->'$.sizes', '["M", "L"]');-- Contains any of these valuesSELECT sku FROM productsWHERE JSON_OVERLAPS(attributes->'$.tags', '["gift", "sale"]');-- Find the path to a valueSELECT JSON_SEARCH(attributes, 'one', 'kitchen') FROM products;  -- "$.tags[0]"

MEMBER OF და JSON_OVERLAPS 8.0.17-ში გამოჩნდა და ეს ორი უნდა დაიმახსოვრო, რადგან სწორედ მათ შეუძლია მოემსახუროს multi-valued index (ქვემოთ). JSON_CONTAINS-იც იყენებს ამ index-ს.

როცა JSON მასივის ხაზებად აღქმა გჭირდება - მასთან join-ისთვის, მისი ელემენტებით დაჯგუფებისთვის ან ექსპორტისთვის - JSON_TABLE დოკუმენტს წარმოებულ ცხრილად აქცევს:

sql
SELECT p.sku, t.tagFROM products p,     JSON_TABLE(p.attributes, '$.tags[*]'       COLUMNS (tag VARCHAR(40) PATH '$')) AS t;

საპირისპირო მიმართულება, ხაზები JSON-ად, არის JSON_OBJECT, JSON_ARRAY და აგრეგატები JSON_ARRAYAGG და JSON_OBJECTAGG, რომლებიც API პასუხის ერთ query-ში აწყობის ყველაზე სუფთა გზაა: SELECT JSON_ARRAYAGG(JSON_OBJECT('sku', sku, 'colour', attributes->>'$.colour')) FROM products.

დოკუმენტის ნაწილის განახლება#

აუცილებელი არ არის, რომ მთელი დოკუმენტი აპლიკაციის კოდში წაიკითხო, შეცვალო და უკან ჩაწერო. MySQL-ს აქვს ფუნქციები, რომლებიც შეცვლილ ასლს აბრუნებენ:

ფუნქციააკეთებს
JSON_SET(doc, path, val)ამატებს ან ცვლის
JSON_INSERT(doc, path, val)ამატებს მხოლოდ მაშინ, თუ path არ არსებობს
JSON_REPLACE(doc, path, val)ცვლის მხოლოდ მაშინ, თუ path არსებობს
JSON_REMOVE(doc, path)შლის path-ს
JSON_ARRAY_APPEND(doc, path, val)ამატებს მასივის ბოლოში
JSON_MERGE_PATCH(doc, patch)იყენებს RFC 7396 merge patch-ს
sql
UPDATE productsSET attributes = JSON_SET(attributes, '$.price', 21.0, '$.on_sale', true)WHERE sku = 'TEE-02';UPDATE productsSET attributes = JSON_ARRAY_APPEND(attributes, '$.tags', 'sale')WHERE sku = 'MUG-01';

SQL-ში გაკეთება მხოლოდ უფრო მოკლე კი არა, პარალელურობის პირობებში უფრო უსაფრთხოცაა. ორი მოთხოვნა, რომლებიც თითოეული დოკუმენტს კითხულობს, სხვადასხვა ველს ცვლის და უკან წერს, ერთ ცვლილებას დაკარგავს. ერთსა და იმავე ხაზზე ორ UPDATE ... JSON_SET ბრძანებას ხაზის lock რიგში აყენებს და ორივე გადარჩება. MySQL-ის ტრანზაქციები, locking და deadlock-ები ამ პრობლემის ზოგად ვერსიას განიხილავს.

როცა JSON_SET, JSON_REPLACE ან JSON_REMOVE სვეტს ადგილზე ანახლებს (SET col = JSON_SET(col, ...)) და ახალი მნიშვნელობა ძველზე დიდი არ არის, InnoDB-ს შეუძლია ნაწილობრივი განახლება გააკეთოს მთელი მნიშვნელობის გადაწერის ნაცვლად. binlog_row_value_options = PARTIAL_JSON-ით binary log-იც მხოლოდ ცვლილებას იწერს. ეს ოპტიმიზაცია SQL-ში განახლებით უფასოდ მიიღება და საერთოდ არ მიიღება, თუ დოკუმენტს აპლიკაციიდან გადაწერ.

JSON_MERGE_PRESERVE (და მისი მოძველებული ფსევდონიმი JSON_MERGE) მასივებს აერთებს და დუბლირებულ გასაღებებს მასივებად აერთიანებს; JSON_MERGE_PATCH მნიშვნელობებს ცვლის, რაც თითქმის ყოველთვის ის არის, რასაც API-ში "patch" ნიშნავს.

JSON-ის დაინდექსება generated სვეტებით#

JSON სვეტი index-ში ვერ მოხვდება. WHERE attributes->>'$.colour' = 'blue' მილიონ ხაზზე მილიონ დოკუმენტს კითხულობს. გამოსავალი generated სვეტია: სვეტი, რომლის მნიშვნელობაც იმავე ხაზის სხვა სვეტებზე გამოსახულებით გამოითვლება.

sql
ALTER TABLE products  ADD COLUMN colour VARCHAR(30)    GENERATED ALWAYS AS (attributes->>'$.colour') VIRTUAL,  ADD INDEX idx_colour (colour);

VIRTUAL სვეტი (ნაგულისხმევი) ხაზის წაკითხვისას გამოითვლება და ცხრილში ადგილს არ იკავებს; InnoDB-ს მაინც შეუძლია ის secondary index-ში ჩასვას, სადაც გამოთვლილი მნიშვნელობა ინახება. STORED სვეტი ჩაწერისას გამოითვლება და ხაზში ინახება, რაც ადგილი ჯდება და მას primary key-ში გამოსაყენებლად ვარგისს ხდის. JSON ველების დაინდექსებისთვის virtual ჩვეულებრივი არჩევანია.

sql
EXPLAIN SELECT sku FROM products WHERE colour = 'blue';-- type: ref, key: idx_colour

query generated სვეტზე მისი სახელით გააკეთე. optimizer-ს ასევე შეუძლია ამოიცნოს თავდაპირველი გამოსახულება და index გამოიყენოს WHERE attributes->>'$.colour' = 'blue'-ისთვის, მაგრამ მხოლოდ მაშინ, როცა გამოსახულება, მისი ტიპი და collation ზუსტად ემთხვევა სვეტის განსაზღვრებას; სვეტის სახელით მიმართვა არასოდეს არის ორაზროვანი. MySQL-ის index-ები და EXPLAIN გეგმის კითხვას განიხილავს.

რაზეც ხალხი წამოეგება:

  • ტიპს მნიშვნელობა აქვს. VARCHAR(30) AS (attributes->>'$.colour') ტექსტს ინახავს. რიცხვისთვის გამოიყენე cast: price DECIMAL(10,2) AS (CAST(attributes->>'$.price' AS DECIMAL(10,2))). დოკუმენტი, რომლის price რიცხვი არ არის, insert-ზე ჩავარდება, რაც ხშირად ზუსტად ის ვალიდაციაა, რაც გინდოდა.
  • სვეტისთვის ზედმეტად გრძელი მნიშვნელობა შეცდომაა strict რეჟიმში, რომელიც 8.4-ის ნაგულისხმევია. generated სვეტის ზომა მონაცემებს მოარგე, თორემ insert ჩავარდება იმ ერთ ხაზზე, რომელსაც გრძელი მნიშვნელობა აქვს.
  • დაშვებულია მხოლოდ დეტერმინისტული გამოსახულებები - არანაირი NOW(), RAND(), მომხმარებლის ცვლადები ან subquery-ები.
  • virtual სვეტის დამატება იაფია; მისი index-ის აგება - არა. სვეტი მეტამონაცემების ცვლილებაა, მაგრამ index-მა ყველა ხაზი უნდა წაიკითხოს. InnoDB მას online აგებს და ამასობაში წაკითხვასა და ჩაწერას უშვებს, მაგრამ დიდ ცხრილზე მაინც დრო და I/O სჭირდება. გააკეთე მშვიდ საათზე.

ფუნქციური და multi-valued index-ები#

8.0.13-დან შეგიძლია სახელიანი სვეტი გამოტოვო და გამოსახულება პირდაპირ დააინდექსო. MySQL შენთვის დამალულ virtual სვეტს ქმნის. სტრიქონების შემთხვევას collation-ის მახე აქვს: CAST(... AS CHAR) ნაგულისხმევ collation-ს იძლევა, ხოლო ->> - utf8mb4_bin-ს, და ერთზე აგებული index მეორესთან შედარებისთვის არ გამოიყენება. MySQL-ის სახელმძღვანელოს საკუთარი გამოსავალი index-ში collation-ის მითითებაა:

sql
ALTER TABLE products  ADD INDEX idx_material ((CAST(attributes->>'$.material' AS CHAR(30))                           COLLATE utf8mb4_bin));SELECT sku FROM products WHERE attributes->>'$.material' = 'steel';

ეს მუშაობს, მაგრამ სახელიანი generated სვეტი უფრო ადვილი წასაკითხია, უფრო ადვილია მასზე query-ის გაკეთება და ჩანს ყველასთვის, ვინც სქემას გახსნის. ის ამჯობინე, თუ საწინააღმდეგო მიზეზი არ გაქვს.

მასივებს სხვა სახის index სჭირდებათ. 8.0.17-დან multi-valued index მასივის თითო ელემენტზე ერთ index ჩანაწერს ინახავს, ასე რომ MEMBER OF-ს, JSON_CONTAINS-სა და JSON_OVERLAPS-ს მისი გამოყენება შეუძლიათ:

sql
CREATE TABLE customers (  id       BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,  name     VARCHAR(100) NOT NULL,  profile  JSON NOT NULL,  INDEX idx_zips ((CAST(profile->'$.zipcodes' AS UNSIGNED ARRAY))));SELECT name FROM customers WHERE 94507 MEMBER OF (profile->'$.zipcodes');

cast-ის ტიპი index-ის ნაწილია - UNSIGNED ARRAY, SIGNED ARRAY, CHAR(n) ARRAY, DATE ARRAY და რამდენიმე სხვა - და დოკუმენტებში მნიშვნელობები მასში უნდა გარდაიქმნებოდეს. multi-valued index-ს მხოლოდ ერთი მასივის გასაღების ნაწილი შეიძლება ჰქონდეს, ვერ იქნება primary ან covering index და გამოიყენება ფილტრაციისთვის, არა დალაგებისთვის.

არსებული TEXT სვეტის JSON-ად გარდაქმნა#

რეალურ სამყაროში ჩვეულებრივი საწყისი წერტილი ახალი ცხრილი კი არა, ძველია, სადაც ვიღაცამ წლების წინ JSON TEXT ან LONGTEXT სვეტში შეინახა. გარდაქმნა გაძლევს ვალიდაციას, ბინარულ ფორმატს და ზემოთ ჩამოთვლილ ყველა ფუნქციას. გარდაქმნა პირველივე არავალიდურ ხაზზე ვარდება, ამიტომ ჯერ ისინი იპოვე:

sql
SELECT id, LEFT(settings, 80) AS previewFROM accountsWHERE settings IS NOT NULL AND JSON_VALID(settings) = 0;

მოელოდე სამი სახის შედეგს. ცარიელ სტრიქონებს, რომლებიც ვალიდური JSON არ არის - გადაწყვიტე, NULL ნიშნავს თუ {}, და განაახლე. დოკუმენტებს ერთმაგი ბრჭყალებით ან ბოლო მძიმეებით, დაწერილს ხელით ან serializer-ით, რომელიც სინამდვილეში JSON-ს არ აწარმოებდა - გაასწორე ისინი იმ აპლიკაციაში, რომელმაც დაწერა, შემდეგ კი მონაცემებში. და PHP-ის serialize()-ის გამონატანს ან მსგავსს, რაც ნიშნავს, რომ სვეტი არასოდეს ყოფილა JSON და სკრიპტი სჭირდება და არა SQL.

როცა query აღარაფერს დააბრუნებს, გარდაქმენი ერთი ბრძანებით:

sql
UPDATE accounts SET settings = '{}' WHERE settings = '';ALTER TABLE accounts MODIFY settings JSON NULL;

სვეტის ტიპის შეცვლა ცხრილს თავიდან აგებს: InnoDB ყველა ხაზს აკოპირებს და ამ დროს პარალელური ჩაწერები დაბლოკილია (ALGORITHM=COPY). რამდენიმე ასეული მეგაბაიტის ცხრილზე ეს წამებიდან წუთებამდეა; უფრო დიდზე დაგეგმე მომსახურების ფანჯარა, ან დაამატე ახალი JSON სვეტი, შეავსე ის ნაწილ-ნაწილ და გადაიყვანე აპლიკაცია, სანამ ძველს წაშლი. ორივე შემთხვევაში ჯერ dump გააკეთე - mysqldump-ით backup და აღდგენა განიხილავს, როგორ გააკეთო ეს ცხრილის დაბლოკვის გარეშე.

ერთი გვერდითი ეფექტი, რომელიც შემდეგ უნდა შეამოწმო: რადგან დოკუმენტები შესვლისას ნორმალიზდება, გასაღებების რიგი და whitespace იცვლება. ყველაფერი, რაც ნედლ ტექსტს ადარებდა - სტრიქონიდან აგებული cache key, checksum, ტესტის fixture - იმავე მონაცემებისთვის სხვა ბაიტებს დაინახავს.

დალაგება და დაჯგუფება JSON ველებით#

ORDER BY attributes->'$.price' მუშაობს, მაგრამ ის JSON მნიშვნელობებს ალაგებს, ხოლო JSON-ის შედარებას საკუთარი წესები აქვს: რიცხვები რიცხვებად ლაგდება, სტრიქონები სტრიქონებად, ხოლო სხვადასხვა JSON ტიპის მნიშვნელობები ჯერ ტიპით, შემდეგ მნიშვნელობით. თუ ზოგი დოკუმენტი ფასს 19.5-ად ინახავს, ზოგი კი "19.50"-ად, ისინი ისე არ შეერევა ერთმანეთს, როგორც ელი. როცა რიგს მნიშვნელობა აქვს, ცხადად გამოიყენე cast - ORDER BY CAST(attributes->>'$.price' AS DECIMAL(10,2)) - და უკეთესია, დაალაგო generated სვეტით ამ cast-ით, რაც index-საც აძლევს საშუალებას, რიგი თავად უზრუნველყოს filesort-ის ნაცვლად.

დაჯგუფებაც იგივეა: GROUP BY attributes->>'$.colour' ტექსტით აჯგუფებს, ამიტომ "Blue" და "blue" ცალკე ჯგუფებია იმ ბინარული collation-ით, რომელსაც ->> აბრუნებს. generated VARCHAR სვეტი ნაგულისხმევი, რეგისტრისადმი არამგრძნობიარე collation-ით მათ ერთად აჯგუფებს. ასეთი პატარა განსხვავებები კარგი არგუმენტია, რომ ყოველი ველი, რომელზეც ანგარიშებს აკეთებ, generated სვეტზე გაატარო გამოცხადებული ტიპითა და collation-ით.

დოკუმენტების ვალიდაცია და როდის არ გამოიყენო JSON#

JSON სვეტი ნებისმიერ ვალიდურ დოკუმენტს იღებს. თუ შენი აპლიკაცია ვარაუდობს, რომ price ყოველთვის რიცხვია, ეს აიძულე, რადგან ის ერთი ხაზი, სადაც ის სტრიქონია, ექვსი თვის შემდეგ ანგარიშში ამოტივტივდება. JSON_SCHEMA_VALID (8.0.17) დოკუმენტს JSON Schema-სთან ამოწმებს, ხოლო CHECK constraint MySQL-ს ამის აღსრულებას ყოველ ჩაწერაზე აიძულებს:

sql
ALTER TABLE products ADD CONSTRAINT attributes_shape CHECK (  JSON_SCHEMA_VALID('{    "type": "object",    "properties": {      "colour": {"type": "string"},      "price":  {"type": "number", "minimum": 0},      "tags":   {"type": "array", "items": {"type": "string"}}    }  }', attributes));

დარღვევა ჩანს როგორც შეცდომა 3819, Check constraint 'attributes_shape' is violated. generated სვეტები cast-ებით იმავე იდეის უფრო მსუბუქი ვერსიაა.

ახლა გულწრფელი ნაწილი. JSON არასწორი არჩევანია, როცა:

  • მასზე join-ს აკეთებ. foreign key-ს დოკუმენტის შიგნით მითითება არ შეუძლია, ამიტომ მითითებითი მთლიანობა ქრება. user_id JSON-ის შიგნით ბაგია, რომელიც წაშლილ მომხმარებელს ელოდება.
  • ყველა ხაზს ერთი და იგივე ველები აქვს. მაშინ ისინი სვეტებია. სვეტები უფრო პატარაა, ტიპიზებული, დაინდექსებადი ზედმეტი ცერემონიის გარეშე და სქემაში ხილული.
  • დიდი დოკუმენტის შიგნით ერთ მთვლელს წამში ბევრჯერ ანახლებ. ყოველი განახლება ხაზს ბლოკავს და, თუ მნიშვნელობა იზრდება, დოკუმენტს თავიდან წერს.
  • მასზე მუდმივად აგრეგაციას აკეთებ. SUM(CAST(attributes->>'$.price' AS DECIMAL)) მთელ ცხრილზე სრული scan-ია, როგორც არ უნდა დააინდექსო.

გონივრული წესი: ფიქსირებული, query-ებში გამოყენებული და join-ში მონაწილე ველები სვეტებია; არჩევითი, იშვიათი ან კლიენტის მიერ განსაზღვრული ველები ერთ JSON სვეტში მიდის; JSON-იდან ნებისმიერი ველი, რომელიც საკმარისად მნიშვნელოვანი გახდება, რომ მასზე გაფილტრო, generated სვეტად index-ით დაწინაურდება. თუ MySQL-ის JSON-სა და დოკუმენტურ ბაზას შორის ირჩევ, MySQL თუ PostgreSQL განიხილავს, როგორ შეედრება PostgreSQL-ის jsonb და GIN index-ები, ხოლო Postgres თუ MongoDB - დოკუმენტური საცავის მხარეს.

FAQ#

JSON სვეტი ჩვეულებრივ სვეტებზე ნელია?

JSON სვეტიდან ერთი ველის წაკითხვა სვეტის წაკითხვაზე ოდნავ ნელია, ხოლო არადაინდექსებულ ველზე ფილტრაცია გაცილებით ნელია, რადგან scan-ს აკეთებს. generated სვეტითა და index-ით იმ ველებზე, რომლებითაც ფილტრავ, query-ები ნებისმიერი დაინდექსებული სვეტივით იქცევა. ბინარული ფორმატის შენახვის overhead ზომიერია, მაგრამ რეალური - გასაღებები ყოველ ხაზში ინახება.

შემიძლია foreign key დავადო JSON-ის შიგნით არსებულ მნიშვნელობას?

პირდაპირ არა. შეგიძლია დაამატო STORED generated სვეტი, რომელიც მნიშვნელობას იღებს, და foreign key ამ სვეტზე დადო, რაც ერთი სკალარისთვის მუშაობს. თუ ამას აკეთებ, მნიშვნელობა ალბათ ჩვეულებრივ სვეტში უნდა იყოს.

რატომ აბრუნებს ჩემი query "blue"-ს ბრჭყალებით?

გამოიყენე -> ან JSON_EXTRACT, რომლებიც JSON მნიშვნელობებს აბრუნებენ, და JSON სტრიქონი თავის ბრჭყალებს შეიცავს. გამოიყენე ->> ან შეფუთე გამოსახულება JSON_UNQUOTE-ში, რომ უბრალო ტექსტი მიიღო.

მუშაობს MySQL-ის JSON ORM-ებთან?

კი. Laravel-ის Eloquent JSON სვეტებს მასივებად გარდაქმნის და where('attributes->colour', 'blue')-ს მხარს უჭერს, Django-ს JSONField MySQL-ს უჭერს მხარს, ხოლო SQLAlchemy-ს JSON ტიპი აქვს. რასაც ORM შენთვის ვერ გააკეთებს, ეს generated სვეტისა და index-ის შექმნაა - ისინი migration-ში დაამატე.

როგორ ვიპოვო დოკუმენტები, რომლებსაც ველი აკლია?

WHERE NOT JSON_CONTAINS_PATH(attributes, 'one', '$.price'). გაითვალისწინე, რომ attributes->>'$.price' IS NULL-იც ემთხვევა დოკუმენტებს, სადაც ველი აკლია, მაგრამ არა იმათ, სადაც ის ცხადი JSON null-ია, რომლებიც სტრიქონ null-ს აბრუნებენ.


კომენტარები

სრულიად ანონიმურად: ანგარიშის, ელფოსტის და cookie-ის გარეშე. ინახება მხოლოდ სახელი, ტექსტი და დრო - სხვა არაფერი. ბმულების რაოდენობა ლიმიტირებულია.

0/2000