পোস্টগ্রিসএসকিউএলে লাইক, সিমিলার টু বা নিয়মিত প্রকাশের সাথে প্যাটার্ন মিল matching


94

আমাকে একটি সাধারণ জিজ্ঞাসা লিখতে হয়েছিল যেখানে আমি বি বা ডি দিয়ে শুরু হওয়া লোকদের নাম খুঁজতে যাচ্ছি:

SELECT s.name 
FROM spelers s 
WHERE s.name LIKE 'B%' OR s.name LIKE 'D%'
ORDER BY 1

আমি ভাবছিলাম যে আরও পারফরম্যান্স হওয়ার জন্য এটি আবার লেখার কোনও উপায় আছে কিনা? সুতরাং আমি এড়াতে পারি orএবং / অথবা like?


আপনি কেন নতুন করে লেখার চেষ্টা করছেন? কর্মক্ষমতা? পরিচ্ছন্নতা? হয় s.nameইন্ডেক্স?
মার্টিন স্মিথ

আমি পারফরম্যান্সের জন্য লিখতে চাই, s.name ইনডেক্স হয় না।
লুকাস কাউফম্যান

8
ঠিক আছে আপনি ওয়াইল্ড কার্ডকে নেতৃত্ব না দিয়ে অনুসন্ধান করছেন এবং কোনও অতিরিক্ত কলাম নির্বাচন না করে এর উপর কোনও সূচক nameএখানে কার্যকর হতে পারে যদি আপনি পারফরম্যান্সের বিষয়ে চিন্তা করেন।
মার্টিন স্মিথ

উত্তর:


161

আপনার জিজ্ঞাসাটি সর্বোত্তম is সিনট্যাক্স খুব বেশি সংক্ষিপ্ত হবে না, ক্যোয়ারী খুব দ্রুত পাবে না:

SELECT name
FROM   spelers
WHERE  name LIKE 'B%' OR name LIKE 'D%'
ORDER  BY 1;

যদি আপনি সত্যিই বাক্য সংক্ষিপ্ত করতে চান তবে শাখাগুলি সহ একটি নিয়মিত প্রকাশটি ব্যবহার করুন :

...
WHERE  name ~ '^(B|D).*'

বা কিছুটা দ্রুত, একটি অক্ষর শ্রেণীর সাথে :

...
WHERE  name ~ '^[BD].*'

সূচক ছাড়াই একটি দ্রুত পরীক্ষা SIMILAR TOআমার পক্ষে উভয় ক্ষেত্রে তুলনায় দ্রুত ফলাফল দেয় ।
যথাযথ বি-ট্রি সূচক সহ, LIKEবিশালতার আদেশে এই রেসটি জয়ী।

ম্যানুয়ালটিতে প্যাটার্ন মিলের বিষয়ে প্রাথমিক বিষয়গুলি পড়ুন ।

উচ্চতর পারফরম্যান্সের জন্য সূচক

আপনি যদি পারফরম্যান্স নিয়ে উদ্বিগ্ন হন তবে বড় টেবিলগুলির জন্য এই জাতীয় সূচি তৈরি করুন:

CREATE INDEX spelers_name_special_idx ON spelers (name text_pattern_ops);

আকারের আদেশ দিয়ে এই ধরণের ক্যোয়ারী দ্রুততর করে তোলে। লোকাল-নির্দিষ্ট সাজানোর ক্রমের জন্য বিশেষ বিবেচনাগুলি প্রযোজ্য। ম্যানুয়ালটিতে অপারেটর ক্লাস সম্পর্কে আরও পড়ুন । আপনি যদি স্ট্যান্ডার্ড "সি" লোকেল ব্যবহার করেন (বেশিরভাগ লোকেরা করেন না), একটি সরল সূচক (ডিফল্ট অপারেটর শ্রেণি সহ) করবে।

এই জাতীয় সূচকটি কেবল বাম-অ্যাঙ্কার্ড প্যাটার্নের জন্য ভাল (স্ট্রিংয়ের শুরু থেকে মিলছে)।

SIMILAR TOবা বেসিক বাম-অ্যাঙ্কার্ড এক্সপ্রেশন সহ নিয়মিত প্রকাশগুলিও এই সূচকটি ব্যবহার করতে পারে। তবে শাখা বা চরিত্রের ক্লাসগুলির সাথে নয় (অন্ততপক্ষে পোস্টগ্রাইএসকিউএল 9.0 এ আমার পরীক্ষাগুলিতে)।(B|D)[BD]

ত্রিগ্রামের মিল বা পাঠ্য অনুসন্ধানে বিশেষ জিন বা জিআইএসটি সূচকগুলি ব্যবহার করা হয়েছে।

প্যাটার্ন ম্যাচিং অপারেটরগুলির ওভারভিউ

  • LIKE( ~~) সহজ এবং দ্রুত তবে এর ক্ষমতাগুলিতে সীমিত।
    ILIKE( ~~*) কেস সংবেদনশীল বৈকল্পিক।
    pg_trgm উভয়ের জন্য সূচী সমর্থন প্রসারিত করে।

  • ~ (নিয়মিত অভিব্যক্তি ম্যাচ) শক্তিশালী তবে আরও জটিল এবং বেসিক এক্সপ্রেশনগুলির চেয়ে বেশি কিছু জন্য ধীর হতে পারে।

  • SIMILAR TOশুধু অর্থহীন । একটি অদ্ভুত অর্ধবৃত্ত LIKEএবং নিয়মিত অভিব্যক্তি। আমি কখনই এটি ব্যবহার করি না। নিচে দেখ.

  • % হ'ল "মিল" অপারেটর, অতিরিক্ত মডিউল দ্বারা সরবরাহ করাpg_trgm। নিচে দেখ.

  • @@এটি পাঠ্য অনুসন্ধান অপারেটর। নিচে দেখ.

pg_trgm - ট্রিগার মিল

পোস্টগ্রেএসকিউএল 9.1 এর সাথে শুরু করে আপনি কোনও জিআইএন বা জিআইএসটি সূচক ব্যবহার করে যে কোনও / প্যাটার্ন (এবং সাধারণ রেজিপ্যাক্স প্যাটার্নগুলি ) এর pg_trgmজন্য সূচী সহায়তা সরবরাহ করতে এক্সটেনশনটিকে সহজতর করতে পারেন । LIKEILIKE~

বিশদ, উদাহরণ এবং লিঙ্কগুলি:

pg_trgmএই অপারেটরগুলি প্রদান করে :

  • % - "মিল" অপারেটর
  • <%( %>চালক:) - পোস্টগ্রাজ 9.6 বা তার পরে "ওয়ার্ড_সিমারিটি" অপারেটর
  • <<%( %>>অভিযাত্রী:) - 11 বা তার পরে পোস্টগ্রিসে "কড়া_শব্দ_সমন্থিতা" অপারেটর

টেক্সট অনুসন্ধান

পৃথক পরিকাঠামো এবং সূচক প্রকারের সাথে এক বিশেষ ধরণের প্যাটার্নের মিল। এটি অভিধান এবং স্টেমিং ব্যবহার করে এবং দস্তাবেজগুলিতে বিশেষত প্রাকৃতিক ভাষার জন্য শব্দগুলি সন্ধান করার জন্য একটি দুর্দান্ত সরঞ্জাম।

উপসর্গ মিলও সমর্থিত:

পোস্টগ্রিস 9.6 থেকে বাক্যাংশ অনুসন্ধানের পাশাপাশি :

বিবেচনা করুন ম্যানুয়াল ভূমিকা এবং অপারেটরদের এবং ফাংশন ওভারভিউ

অস্পষ্ট স্ট্রিং মিলের জন্য অতিরিক্ত সরঞ্জাম

অতিরিক্ত মডিউল ফাজিস্ট্রমেটম আরও কয়েকটি বিকল্প সরবরাহ করে তবে কার্য সম্পাদন উপরের সমস্তটির চেয়ে সাধারণত নিকৃষ্ট হয়।

বিশেষত, levenshtein()ফাংশনের বিভিন্ন বাস্তবায়ন সহায়ক হতে পারে।

নিয়মিত এক্সপ্রেশন ( ~) সবসময় কেন দ্রুত হয় SIMILAR TO?

উত্তরটি সহজ। SIMILAR TOঅভিব্যক্তিগুলি অভ্যন্তরীণভাবে নিয়মিত প্রকাশে আবার লেখা হয়। সুতরাং, প্রতিটি SIMILAR TOঅভিব্যক্তির জন্য, কমপক্ষে একটি দ্রুত নিয়মিত এক্সপ্রেশন থাকে (যা এক্সপ্রেশনটি পুনরায় লেখার ওভারহেড সংরক্ষণ করে)। SIMILAR TO কখনও ব্যবহার করে কোনও পারফরম্যান্স লাভ হয় না ।

এবং LIKE( ~~) দিয়ে করা যায় এমন সাধারণ এক্সপ্রেশন LIKEযেভাবেই দ্রুত হয় ।

SIMILAR TOএটি কেবল পোস্টগ্রাইএসকিউএলে সমর্থিত কারণ এটি এসকিউএল স্ট্যান্ডার্ডের প্রারম্ভিক খসড়াগুলিতে শেষ হয়েছিল। তারা এখনও এ থেকে মুক্তি পান নি। তবে এটি সরানোর এবং এর পরিবর্তে রিজেপএক্স ম্যাচগুলি অন্তর্ভুক্ত করার পরিকল্পনা রয়েছে - বা তাই শুনেছি।

EXPLAIN ANALYZEএটি প্রকাশ করে। যে কোনও টেবিলে নিজে চেষ্টা করুন!

EXPLAIN ANALYZE SELECT * FROM spelers WHERE name SIMILAR TO 'B%';

প্রকাশিত:

...  
Seq Scan on spelers  (cost= ...  
  Filter: (name ~ '^(?:B.*)$'::text)

SIMILAR TOনিয়মিত অভিব্যক্তি ( ~) দিয়ে আবার লেখা হয়েছিল ।

এই বিশেষ ক্ষেত্রে চূড়ান্ত কর্মক্ষমতা

তবে EXPLAIN ANALYZEআরও প্রকাশ করে। পূর্বে উল্লিখিত সূচীটি সহ চেষ্টা করুন:

EXPLAIN ANALYZE SELECT * FROM spelers WHERE name ~ '^B.*;

প্রকাশিত:

...
 ->  Bitmap Heap Scan on spelers  (cost= ...
       Filter: (name ~ '^B.*'::text)
        ->  Bitmap Index Scan on spelers_name_text_pattern_ops_idx (cost= ...
              Index Cond: ((prod ~>=~ 'B'::text) AND (prod ~<~ 'C'::text))

অভ্যন্তরীণভাবে, একটি সূচক (যে স্থানীয়ের সচেতন নয় সঙ্গে text_pattern_opsবা ব্যবহার লোকেল C:) সহজ বাঁ-নোঙর এক্সপ্রেশন এই টেক্সট প্যাটার্ন অপারেটরদের সঙ্গে পুনর্লিখিত হয় ~>=~, ~<=~, ~>~, ~<~। এই ক্ষেত্রে দেখা যায় ~, ~~বা SIMILAR TOসমান মনে করে।

একই বা সাথে varcharপ্রকারের সূচকগুলির ক্ষেত্রেও এটি সত্য ।varchar_pattern_opscharbpchar_pattern_ops

সুতরাং, আসল প্রশ্নের ক্ষেত্রে প্রয়োগ করা, এটি সবচেয়ে দ্রুততম উপায় :

SELECT name
FROM   spelers  
WHERE  name ~>=~ 'B' AND name ~<~ 'C'
    OR name ~>=~ 'D' AND name ~<~ 'E'
ORDER  BY 1;

অবশ্যই, যদি আপনার নিকটবর্তী প্রাথমিকের সন্ধানের ঘটনা ঘটে তবে আপনি আরও সহজ করতে পারেন:

WHERE  name ~>=~ 'B' AND name ~<~ 'D'   -- strings starting with B or C

এর সাধারণ ব্যবহার ~বা লাভ ~~খুব সামান্য is যদি পারফরম্যান্সটি আপনার সর্বজনীন প্রয়োজন না হয় তবে আপনার কেবল স্ট্যান্ডার্ড অপারেটরদের সাথে থাকা উচিত - আপনার ইতিমধ্যে প্রশ্নটিতে যা আছে তা পৌঁছে।


ওপিতে নামেরটিতে কোনও সূচক নেই তবে আপনি কি তা জানতে পেরেছেন, যদি তারা তা করে থাকে তবে তাদের আসল জিজ্ঞাসায় 2 সীমাবদ্ধতা এবং similarএকটি স্ক্যান জড়িত থাকতে পারে ?
মার্টিন স্মিথ

2
@ মার্টিনস্মিথ: EXPLAIN ANALYZE2 বিটম্যাপ সূচক স্ক্যানগুলির সাথে একটি দ্রুত পরীক্ষা । একাধিক বিটম্যাপ সূচক স্ক্যানগুলি বরং দ্রুত সংযুক্ত করা যায়।
এরউইন ব্র্যান্ডসেটেটার

ধন্যবাদ। তাই সেখানে প্রতিস্থাপন সঙ্গে কোনো যত মাইল দীর্ঘ হবে ORসঙ্গে UNION ALLবা প্রতিস্থাপন name LIKE 'B%'সঙ্গে name >= 'B' AND name <'C'Postgres মধ্যে?
মার্টিন স্মিথ

1
@ মার্টিনস্মিথ: UNIONতবে হ্যাঁ না, রেঞ্জগুলি একটি ধারাতে একত্রিত WHEREকরলে ক্যোয়ারী দ্রুত হবে। আমি আমার উত্তরে আরও যুক্ত করেছি। অবশ্যই আপনাকে নিজের লোকালটি অ্যাকাউন্টে নিতে হবে। স্থানীয়-সচেতন অনুসন্ধান সর্বদা ধীর।
এরউইন ব্র্যান্ডসটেটার

2
@ এ_হর্স_বিহীন_নাম_নাম: আমি আশা করি না। জিআইএন সূচকগুলির সাথে pg_tgrm এর নতুন ক্ষমতাগুলি জেনেরিক পাঠ্য সন্ধানের জন্য ট্রিট। শুরুতে অ্যাঙ্করড একটি অনুসন্ধান ইতিমধ্যে এর চেয়ে দ্রুত।
এরউইন ব্র্যান্ডসেটেটার

11

টেবিলে একটি কলাম যুক্ত করার বিষয়ে কীভাবে। আপনার প্রকৃত প্রয়োজনীয়তার উপর নির্ভর করে:

person_name_start_with_B_or_D (Boolean)

person_name_start_with_char CHAR(1)

person_name_start_with VARCHAR(30)

পোস্টগ্রেএসকিউএল একটি লা এসকিউএল সার্ভার বেস টেবিলগুলিতে গণিত কলামগুলিকে সমর্থন করে না তবে নতুন কলামটি ট্রিগারের মাধ্যমে বজায় রাখা যায়। স্পষ্টতই, এই নতুন কলামটি সূচিযুক্ত হবে।

বিকল্পভাবে, একটি অভিব্যক্তির একটি সূচক আপনাকে একই, সস্তা দেবে। উদাহরণ:

CREATE INDEX spelers_name_initial_idx ON spelers (left(name, 1)); 

তাদের অবস্থার সাথে অভিব্যক্তিটির সাথে মিলে যাওয়া অনুসন্ধানগুলি এই সূচকটি ব্যবহার করতে পারে।

এই উপাত্তটি তৈরি করা বা সংশোধন করা হলে এই পারফরম্যান্স হিট নেওয়া হয়, সুতরাং কেবলমাত্র কম কার্যকলাপের পরিবেশের জন্য উপযুক্ত হতে পারে (অর্থাত পঠনের চেয়ে অনেক কম লেখেন)।


8

আপনি চেষ্টা করতে পারেন

SELECT s.name
FROM   spelers s
WHERE  s.name SIMILAR TO '(B|D)%' 
ORDER  BY s.name

উপরের বা আপনার মূল প্রকাশটি পোস্টগ্র্রেসে যদিও ব্যয়বহুল তা আমি জানি না।

আপনি যদি প্রস্তাবিত সূচকটি তৈরি করেন তবে এটি অন্যান্য বিকল্পগুলির সাথে কীভাবে তুলনা করে তা শুনতে আগ্রহী।

SELECT name
FROM   spelers
WHERE  name >= 'B' AND name < 'C'
UNION ALL
SELECT name
FROM   spelers
WHERE  name >= 'D' AND name < 'E'
ORDER  BY name

1
এটি কাজ করেছে এবং আমার 1.19 এর ব্যয় হয়েছে যেখানে আমার 1.25 ছিল। ধন্যবাদ!
লুকাস কাউফম্যান

2

আমি অতীতে যা করেছি, একইরকম পারফরম্যান্স সমস্যার মুখোমুখি হয়েছি তা হ'ল শেষ চিঠির ASCII চরিত্রটিকে বাড়িয়ে তুলতে হবে এবং একটি বিটুইইন করব। তারপরে LIKE কার্যকারিতার একটি উপসেটের জন্য আপনি সেরা পারফরম্যান্স পান। অবশ্যই এটি কিছু নির্দিষ্ট পরিস্থিতিতে কাজ করে তবে অতি-বৃহত্তর ডেটাসেটগুলির জন্য যেখানে আপনি উদাহরণের জন্য কোনও নাম অনুসন্ধান করছেন, এটি সম্পাদনকে অস্বাভাবিক থেকে গ্রহণযোগ্য করে তোলে।


2

খুব পুরানো প্রশ্ন, তবে আমি এই সমস্যার আর একটি দ্রুত সমাধান পেয়েছি:

SELECT s.name 
FROM spelers s 
WHERE ascii(s.name) in (ascii('B'),ascii('D'))
ORDER BY 1

যেহেতু ফাংশন ascii () কেবল স্ট্রিংয়ের প্রথম অক্ষরে দেখায়।


1
এটি কি কোনও সূচক ব্যবহার করে (name)?
ypercubeᵀᴹ

2

আদ্যক্ষর পরীক্ষা করার জন্য, আমি প্রায়শই কাস্টিং ব্যবহার করি "char"(ডাবল উদ্ধৃতি সহ)। এটি বহনযোগ্য নয়, তবে খুব দ্রুত। অভ্যন্তরীণভাবে, এটি টেক্সটটি কেবল বিচ্ছিন্ন করে এবং প্রথম চরিত্রটি দেয় এবং "চর" তুলনা কার্যক্রম খুব দ্রুত হয় কারণ প্রকারটি 1-বাইট স্থির দৈর্ঘ্যের:

SELECT s.name 
FROM spelers s 
WHERE s.name::"char" =ANY( ARRAY[ "char" 'B', 'D' ] )
ORDER BY 1

নোট করুন যে কাস্টিংটি @ Sole021 দ্বারা বিভ্রান্তির "char"চেয়ে দ্রুত ascii(), তবে এটি ইউটিএফ 8 সামঞ্জস্যপূর্ণ নয় (বা সেই বিষয়ে অন্য কোনও এনকোডিং) নয়, কেবল প্রথম বাইটটি ফিরছে, তাই কেবল সেই ক্ষেত্রে ব্যবহার করা উচিত যেখানে তুলনাটি সরল পুরাতন 7 এর বিপরীতে রয়েছে is - ASCII অক্ষর অনুসারে।


1

এ জাতীয় মামলা মোকাবেলার জন্য এখনও দুটি পদ্ধতি উল্লেখ করা হয়নি:

  1. আংশিক (বা বিভাজনযুক্ত - যদি ম্যানুয়ালি পুরো পরিসরের জন্য তৈরি করা হয়) সূচক - তখন কেবল দরকারী যখন কেবলমাত্র একটি উপসেট প্রয়োজন (উদাহরণস্বরূপ কিছু রক্ষণাবেক্ষণের সময় বা কিছু প্রতিবেদনের জন্য অস্থায়ী):

    CREATE INDEX ON spelers WHERE name LIKE 'B%'
  2. টেবিলটি নিজেই বিভাজন (পার্টিশন কী হিসাবে প্রথম চরিত্রটি ব্যবহার করে) - এই কৌশলটি বিশেষত পোস্টগ্রেএসকিউএল 10+ (কম বেদনাদায়ক পার্টিশন) এবং 11+ (ক্যোয়ারী এক্সিকিউশন চলাকালীন পার্টিশন ছাঁটাই) বিবেচনা করার জন্য উপযুক্ত।

তদুপরি, যদি কোনও টেবিলের ডেটা বাছাই করা হয় তবে বিআআআআআআআআআআএনএন (প্রথম অক্ষরের উপরে) ব্যবহার করে কেউ উপকৃত হতে পারেন ।


-4

একটি একক চরিত্রের তুলনা করতে সম্ভবত দ্রুত:

SUBSTR(s.name,1,1)='B' OR SUBSTR(s.name,1,1)='D'

1
আসলে তা না. column LIKE 'B%'কলামে সাবস্ট্রিং ফাংশন ব্যবহার করার চেয়ে আরও দক্ষ হবে।
ypercubeᵀᴹ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.