একটি JSON অ্যারেতে উপাদান খুঁজে পাওয়ার জন্য সূচক


85

আমার দেখতে এমন একটি টেবিল রয়েছে যা দেখতে:

CREATE TABLE tracks (id SERIAL, artists JSON);

INSERT INTO tracks (id, artists) 
  VALUES (1, '[{"name": "blink-182"}]');

INSERT INTO tracks (id, artists) 
  VALUES (2, '[{"name": "The Dirty Heads"}, {"name": "Louis Richards"}]');

আরও কয়েকটি কলাম রয়েছে যা এই প্রশ্নের সাথে সম্পর্কিত নয়। এগুলিকে জেএসএন হিসাবে সংরক্ষণ করার কারণ রয়েছে।

আমি যা করার চেষ্টা করছি তা হ'ল একটি ট্র্যাকের সুনির্দিষ্ট শিল্পীর নাম (সঠিক মিল) lookup

আমি এই প্রশ্নটি ব্যবহার করছি:

SELECT * FROM tracks 
  WHERE 'ARTIST NAME' IN
    (SELECT value->>'name' FROM json_array_elements(artists))

উদাহরণ স্বরূপ

SELECT * FROM tracks
  WHERE 'The Dirty Heads' IN 
    (SELECT value->>'name' FROM json_array_elements(artists))

তবে এটি একটি পূর্ণ টেবিল স্ক্যান করে এবং এটি খুব দ্রুত হয় না। আমি একটি ফাংশন ব্যবহার করে একটি জিআইএন সূচক তৈরি করার চেষ্টা করেছি names_as_array(artists)এবং ব্যবহার করেছি 'ARTIST NAME' = ANY names_as_array(artists), তবে সূচকটি ব্যবহার করা হয়নি এবং ক্যোয়ারীটি আসলে উল্লেখযোগ্যভাবে ধীর।


আমি এটির উপর ভিত্তি করে একটি ফলোআপ প্রশ্ন করেছি: dba.stackexchange.com/questions/71546/…
কেন লি

উত্তর:


142

jsonb পোস্টগ্রিস 9.4+ এ

নতুন বাইনারি JSON ডেটা টাইপের সাথে jsonb, পোস্টগ্রিস 9.4 মূলত উন্নত সূচক বিকল্পগুলি প্রবর্তন করেছে । আপনার কাছে এখন jsonbসরাসরি অ্যারেতে একটি জিআইএন সূচক থাকতে পারে :

CREATE TABLE tracks (id serial, artists jsonb);
CREATE INDEX tracks_artists_gin_idx ON tracks USING gin (artists);

অ্যারে রূপান্তর করতে কোনও ফাংশনের প্রয়োজন নেই। এটি একটি কোয়েরিকে সমর্থন করবে:

SELECT * FROM tracks WHERE artists @> '[{"name": "The Dirty Heads"}]';

@>নতুন হিসাবে jsonb"অপরিবর্তিত" অপারেটর , যা জিআইএন সূচকটি ব্যবহার করতে পারে। ( jsonকেবল টাইপের জন্য নয় jsonb!)

অথবা আপনি jsonb_path_opsসূচকের জন্য আরও বিশেষায়িত, অ-ডিফল্ট জিআইএন অপারেটর শ্রেণি ব্যবহার করেন:

CREATE INDEX tracks_artists_gin_idx ON tracks
USING  gin (artists jsonb_path_ops);

একই প্রশ্ন।

বর্তমানে jsonb_path_opsকেবল @>অপারেটরকে সমর্থন করে । তবে এটি সাধারণত অনেক ছোট এবং দ্রুত। আরো সূচক বিকল্প হয় ম্যানুয়াল ইন বিশদ


artistsউদাহরণে প্রদর্শিত নাম অনুসারে যদি কেবল নাম ধারণ করে থাকে তবে এটি শুরু করার জন্য কম রিডানড্যান্ট জেএসওএন মান সংরক্ষণ করা আরও দক্ষ হবে: কেবল পাঠ্য আদিম হিসাবে মূল্যবোধ এবং অপ্রয়োজনীয় কী কলামের নাম হতে পারে।

JSON অবজেক্ট এবং আদিম ধরণের মধ্যে পার্থক্যটি নোট করুন:

CREATE TABLE tracks (id serial, artistnames jsonb);
INSERT INTO tracks  VALUES (2, '["The Dirty Heads", "Louis Richards"]');

CREATE INDEX tracks_artistnames_gin_idx ON tracks USING gin (artistnames);

প্রশ্ন:

SELECT * FROM tracks WHERE artistnames ? 'The Dirty Heads';

?অবজেক্ট মান , কেবল কী এবং অ্যারের উপাদানগুলির জন্য কাজ করে না ।
বা (নামগুলি পুনরাবৃত্তি করা হলে আরও কার্যকর):

CREATE INDEX tracks_artistnames_gin_idx ON tracks
USING  gin (artistnames jsonb_path_ops);

প্রশ্ন:

SELECT * FROM tracks WHERE artistnames @> '"The Dirty Heads"'::jsonb;

json পোস্টগ্রিস 9.3+ এ

এটি একটি IMMUTABLE ফাংশন সঙ্গে কাজ করা উচিত :

CREATE OR REPLACE FUNCTION json2arr(_j json, _key text)
  RETURNS text[] LANGUAGE sql IMMUTABLE AS
'SELECT ARRAY(SELECT elem->>_key FROM json_array_elements(_j) elem)';

এই ক্রিয়ামূলক সূচক তৈরি করুন :

CREATE INDEX tracks_artists_gin_idx ON tracks
USING  gin (json2arr(artists, 'name'));

এবং এই জাতীয় একটি কোয়েরি ব্যবহার করুন । ধারাটিতে প্রকাশের WHEREসূচকটির সাথে একটিটির সাথে মিল থাকতে হবে:

SELECT * FROM tracks
WHERE  '{"The Dirty Heads"}'::text[] <@ (json2arr(artists, 'name'));

মন্তব্যে মতামত নিয়ে আপডেট হয়েছে। জিআইএন সূচককে সমর্থন করতে আমাদের অ্যারে অপারেটর ব্যবহার করতে হবে । অপারেটর "দ্বারা অন্তর্ভুক্ত করা হয়" এই ক্ষেত্রে।
<@

ফাংশন অস্থিরতা নোট

তুমি তোমার ফাংশন ডিক্লেয়ার করতে পারেন IMMUTABLEএমনকি যদি json_array_elements() না হয় ছিল না।
বেশিরভাগ JSONফাংশন শুধুমাত্র ব্যবহৃত হত STABLE, না IMMUTABLEএটি পরিবর্তন করতে হ্যাকারদের তালিকায় একটি আলোচনা হয়েছিল। বেশিরভাগ IMMUTABLEএখন আছেন। পরিক্ষা কর:

SELECT p.proname, p.provolatile
FROM   pg_proc p
JOIN   pg_namespace n ON n.oid = p.pronamespace
WHERE  n.nspname = 'pg_catalog'
AND    p.proname ~~* '%json%';

কার্যকরী সূচীগুলি কেবল IMMUTABLEফাংশনগুলির সাথে কাজ করে।


4
এটি কাজ করে না কারণ ফেরত দেওয়া SETOFকোনও সূচীতে ব্যবহার করা যায় না। এটি অপসারণ করে, আমি সূচিটি তৈরি করতে পারি, তবে এটি ক্যোয়ার পরিকল্পনাকারী ব্যবহার করে না। এছাড়াও, json_array_elements এবং অ্যারে_আগ উভয়ই হ'লIMMUTABLE
জেফএস

4
@ টনি: দুঃখিত, আমি কলামের নাম এবং কী নাম মিশ্রিত করছিলাম। স্থির এবং আরও যুক্ত।
এরউইন ব্র্যান্ডসটেটার

4
@ পাইওয়াইবি ডিজাইন: জসনব কনটেন্ট ক্যোয়ারীগুলি সাধারণত ধারণকারী উপাদানটির মতো একই কাঠামোর সাথে মিলিয়ে যেতে হবে (সুতরাং অ্যারের অভ্যন্তরে কোনও অবজেক্ট অনুসন্ধান করার অর্থ আপনাকে অবশ্যই অ্যারের অভ্যন্তরে কোনও অবজেক্ট ব্যবহার করে জিজ্ঞাসা করতে হবে)। অ্যারের ভিতরে আদিম ধরণের জন্য একটি বিশেষ ব্যতিক্রম রয়েছে; এখানে আরো বিবরণ: stackoverflow.com/a/29947194/818187
potatosalad

4
@ পাইওয়াইব ডিজাইন: আমি এখন দেখছি, অ্যারে স্তরটি একটি উদাহরণে অনুপস্থিত। স্থির। সূচকটি কেবলমাত্র একটি বৃহত টেবিলে ব্যবহৃত হতে চলেছে যাতে এটি পোস্টগ্রিসের জন্য সিক্যুয়াল স্ক্যানের চেয়ে সস্তা।
এরউইন ব্র্যান্ডসটেটার

4
@PyWebDesign: আপনার সেশনে রান SET enable_seqscan = off;(ডিবাগ করার উদ্দেশ্যে শুধুমাত্র জন্য) stackoverflow.com/questions/14554302/...
এরউইন ব্র্যান্ডসটেটার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.