অনুসন্ধানের স্ট্রিং দীর্ঘায়িত হওয়ায় ত্রিগ্রাম অনুসন্ধান অনেক ধীর হয়ে যায়


16

পোস্টগ্রিস 9.1 ডাটাবেসে আমার কাছে table11.5 টাকার সারি এবং একটি কলাম সহ একটি টেবিল রয়েছে label(এই প্রশ্নের জন্য সহজ সরল নাম)।

সেখানে একটি কার্যকরী ত্রিগ্রাম-সূচক রয়েছে lower(unaccent(label))( সূচকে unaccent()এটির ব্যবহারের অনুমতি দেওয়ার জন্য অচল করে দেওয়া হয়েছে)।

নিম্নলিখিত ক্যোয়ারী বেশ দ্রুত:

SELECT count(*) FROM table1
WHERE (lower(unaccent(label)) like lower(unaccent('%someword%')));
 count 
-------
     1
(1 row)

Time: 394,295 ms

তবে নিম্নলিখিত কোয়েরিটি ধীর:

SELECT count(*) FROM table1
WHERE (lower(unaccent(label)) like lower(unaccent('%someword and some more%')));
 count 
-------
     1
(1 row)

Time: 1405,749 ms

অনুসন্ধান আরও কঠোর হলেও আরও শব্দ যুক্ত করা এমনকি ধীর।

আমি প্রথম শব্দের জন্য একটি সাবকিউারি চালানোর জন্য একটি সাধারণ কৌশল চেষ্টা করেছি এবং তারপরে সম্পূর্ণ অনুসন্ধানের স্ট্রিং সহ একটি কোয়েরি করেছি, তবে (দুঃখের সাথে) ক্যোয়ারির পরিকল্পনাকারী আমার কৌশলগুলি দেখেছি:

EXPLAIN ANALYZE
SELECT * FROM (
   SELECT id, title, label from table1
   WHERE lower(unaccent(label)) like lower(unaccent('%someword%'))
   ) t1
WHERE lower(unaccent(label)) like lower(unaccent('%someword and some more%'));
টেবিল 1 এ বিটম্যাপ হ্যাপ স্ক্যান (ব্যয় = 16216.01..16220.04 সারি = 1 প্রস্থ = 212) (প্রকৃত সময় = 1824.017..1824.019 সারি = 1 লুপ = 1)
  পুনঃপরীক্ষার অবস্থা: ((নিম্ন (অবাস্তব ((লেবেল) :: পাঠ্য))) ~~ '% কিছু শব্দ%' :: পাঠ্য) এবং (নিম্ন (অবাস্তব ((লেবেল) :: পাঠ্য)))% '% কিছু শব্দ এবং আরও কিছু % ':: পাঠ্য))
  -> টেবিল 1_লাবেল_হুন_গিন_টিগ্রামে বিটম্যাপ সূচক স্ক্যান (ব্যয় = 0.00..16216.01 সারি = 1 প্রস্থ = 0) (প্রকৃত সময় = 1823.900..1823.900 সারি = 1 লুপ = 1)
        সূচকের অবস্থা: ((নিম্ন (অচেতন ((লেবেল) :: পাঠ্য))) ~~ '% কিছু শব্দ%' :: পাঠ্য) এবং (নিম্ন (অবাস্তব ((লেবেল) :: পাঠ্য)))% '% কিছু শব্দ এবং আরও কিছু % ':: পাঠ্য))
মোট রানটাইম: 1824.064 এমএস

আমার চূড়ান্ত সমস্যাটি হ'ল অনুসন্ধানের স্ট্রিংটি একটি ওয়েব ইন্টারফেস থেকে আসে যা বেশ দীর্ঘ স্ট্রিং প্রেরণ করতে পারে এবং এটি বেশ ধীর হতে পারে এবং ডস ভেক্টরও গঠন করতে পারে।

সুতরাং আমার প্রশ্নগুলি হ'ল:

  • কীভাবে ক্যারিয়ারটি গতিময় করবেন?
  • এটি দ্রুততর করার জন্য কি এটিকে উপবিভাজনে ভাঙ্গার কোনও উপায় আছে?
  • পোস্টগ্রিসের পরবর্তী সংস্করণটি আরও ভাল? (আমি 9.4 চেষ্টা করেছি এবং এটি দ্রুত বলে মনে হচ্ছে না: এখনও একই প্রভাব Maybe সম্ভবত পরবর্তী সংস্করণ?)
  • অন্য একটি সূচক কৌশল প্রয়োজন হতে পারে?

1
এটি অবশ্যই উল্লেখ করতে হবে যে unaccent()অতিরিক্ত মডিউল দ্বারা সরবরাহ করাও রয়েছে এবং পোস্টগ্রিস ডিফল্টরূপে ফাংশনটিতে সূচিগুলি সমর্থন করে না কারণ এটি নেই IMMUTABLE। আপনার অবশ্যই কিছু পরিবর্তন হয়েছে এবং আপনার প্রশ্নে আপনি ঠিক কী করেছেন তা উল্লেখ করা উচিত। আমার স্থায়ী পরামর্শ: stackoverflow.com/a/11007216/939860 । এছাড়াও, ট্রাইগ্রাম সূচিগুলি বাক্সের বাইরে কেস-সংবেদনশীল ম্যাচ সমর্থন করে। আপনি এটিকে সরল করতে পারেন: WHERE f_unaccent(label) ILIKE f_unaccent('%someword%')- একটি ম্যাচিং সূচক সহ। বিশদ: স্ট্যাকওভারফ্লো . com / a / 28636000 / 939860
এরউইন ব্র্যান্ডসেটেটার

আমি কেবল unaccentঅপরিবর্তনীয় ঘোষণা করেছিলাম । আমি এই প্রশ্নের সাথে যোগ।
P.Péter

আপনি যখন unaccentমডিউলটি আপডেট করবেন তখন হ্যাকটি ওভাররাইট হয়েছে সে বিষয়ে সচেতন থাকুন । আমি এর পরিবর্তে কোনও ফাংশন র‌্যাপারের পরামর্শ দেওয়ার একটি কারণ।
এরউইন ব্র্যান্ডসেটেটার

উত্তর:


34

PostgreSQL 9.6 এ pg_trgm, 1.2 এর একটি নতুন সংস্করণ থাকবে যা এটি সম্পর্কে আরও ভাল হবে। কিছুটা চেষ্টা করে, আপনি পোস্টগ্রিজ এসকিউএল 9.4 এর অধীনে কাজ করতে এই নতুন সংস্করণটিও পেতে পারেন (আপনাকে প্যাচটি প্রয়োগ করতে হবে এবং নিজে এক্সটেনশন মডিউলটি সংকলন করে ইনস্টল করতে হবে)।

প্রাচীনতম সংস্করণটি যা করে তা হ'ল ক্যোয়ারিতে প্রতিটি ট্রিগারের জন্য অনুসন্ধান করা এবং সেগুলির ইউনিয়ন নেওয়া, এবং তারপরে একটি ফিল্টার প্রয়োগ করুন। নতুন সংস্করণটি যা করবে তা হ'ল ক্যোয়ারীতে বিরল ট্রিগারটি বেছে নিন এবং কেবল এটির জন্য অনুসন্ধান করুন এবং তারপরে বাকীগুলিতে পরে ফিল্টার করুন।

এটি করার যন্ত্রপাতি 9.1 সালে বিদ্যমান নেই। 9.4-এ সেই যন্ত্রটি যুক্ত করা হয়েছিল, তবে pg_trgm সেই সময়ে এটির ব্যবহারের জন্য অভিযোজিত হয়নি।

আপনার এখনও একটি সম্ভাব্য ডস ইস্যু থাকতে পারে, কারণ দূষিত ব্যক্তি এমন একটি ক্যোয়ারী তৈরি করতে পারে যার কেবল সাধারণ ট্রিগার রয়েছে। '% এবং%', বা '% a%' এর মতো


আপনি যদি pg_trgm 1.2 এ আপগ্রেড করতে না পারেন, তবে পরিকল্পনাকারীকে ঠকানোর আরও একটি উপায় হ'ল:

WHERE (lower(unaccent(label)) like lower(unaccent('%someword%'))) 
AND   (lower(unaccent(label||'')) like 
      lower(unaccent('%someword and some more%')));

খালি স্ট্রিংটি লেবেলে যুক্ত করে, আপনি পরিকল্পনাকারীকে এমন ভাবাতে প্ররোচিত করেন যেখানে এটির ধারাটির অংশটি সূচকটি ব্যবহার করতে পারে না। সুতরাং এটি সূচকটি%% কিছু% এর উপর ব্যবহার করে এবং কেবলমাত্র এই সারিগুলিতে একটি ফিল্টার প্রয়োগ করে।


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


13
প্যাচ লেখার ক্ষেত্রে আপনিই ছিলেন বলে উল্লেখযোগ্য। এবং প্রাথমিক পারফরম্যান্স পরীক্ষাগুলি চিত্তাকর্ষক। এটি প্রকৃতপক্ষে আরও উন্নয়নের দাবিদার (বর্তমান সংস্করণটির সাথে ব্যাখ্যা এবং কার্যকারণের জন্যও)।
এরউইন ব্র্যান্ডসেটেটার

আপনি 9.1 সালে যে প্যাচটি ছিল না সেগুলি প্রয়োগ করার জন্য আপনি যে যন্ত্রপাতিটি ব্যবহার করেছিলেন তার কমপক্ষে একটি রেফারেন্সে আমি আগ্রহী। তবে, আমি ডাব্লু / এরউইন খারাপ গাধা উত্তর সম্মত।
ইভান ক্যারল 16

3

আমি ক্যোয়ারী পরিকল্পনাকারীকে কেলেঙ্কারী করার একটি উপায় খুঁজে পেয়েছি, এটি বেশ সহজ হ্যাক:

SELECT *
FROM (
   select id, title, label
   from   table1
   where  lower(unaccent(label)) like lower(unaccent('%someword%'))
   ) t1
WHERE lower(lower(unaccent(label))) like lower(unaccent('%someword and more%'))

EXPLAIN আউটপুট:

টেবিল 1 এ বিটম্যাপ হ্যাপ স্ক্যান (দাম = 6749.11..7332.71 সারি = 1 প্রস্থ = 212) (আসল সময় = 256.607..256.609 সারি = 1 লুপ = 1)
  পুনঃপরীক্ষার অবস্থা: (নিম্ন (অচেতন ((লেবেল_হুন) :: পাঠ্য))) ~~ '% কিছু শব্দ%' :: পাঠ্য)
  ফিল্টার: (নিম্ন (নিম্ন (অবাস্তব ((লেবেল) :: পাঠ্য))))% '% কিছু শব্দ এবং আরও কিছু%' :: পাঠ্য)
  -> টেবিল 1_লাবেল_হুন_গিন_টিআরজি তে বিটম্যাপ সূচক স্ক্যান (ব্যয় = 0.00..6749.11 সারি = 147 প্রস্থ = 0) (আসল সময় = 256.499..256.499 সারি = 1 লুপ = 1)
        সূচকের অবস্থা: (নিম্ন (অচেতন ((লেবেল) :: পাঠ্য)) ~~ '% কিছু শব্দ%' :: পাঠ্য)
মোট রানটাইম: 256.653 এমএস

সুতরাং, এর জন্য কোনও সূচক না থাকায় lower(lower(unaccent(label)))এটি একটি ক্রমিক স্ক্যান তৈরি করবে, সুতরাং এটি একটি সাধারণ ফিল্টারে পরিণত হবে। আরও কি, একটি সাধারণ এবং একই জিনিসটি করবে:

SELECT id, title, label
FROM table1
WHERE lower(unaccent(label)) like lower(unaccent('%someword%'))
AND   lower(lower(unaccent(label))) like lower(unaccent('%someword and more%'))

অবশ্যই, এটি একটি হিউরিস্টিক যা খুব ভাল কাজ করতে পারে না, যদি সূচক স্ক্যানে ব্যবহৃত কাট-আউট অংশটি খুব সাধারণ হয়। তবে আমাদের ডাটাবেসে, আমি যদি প্রায় 10-15 অক্ষর ব্যবহার করি তবে সত্যিকারের এত পুনরাবৃত্তি হয় না।

দুটি ছোট প্রশ্ন বাকি আছে:

  • পোস্টগ্রাগস কেন এইরকম কিছু উপকারী হবে তা বুঝতে পারছেন না?
  • পোস্টগ্রিজ 0..256.499 সময়সীমার মধ্যে কি করবে (আউটপুট বিশ্লেষণ দেখুন)?

1
0 থেকে 256.499 এর মধ্যে সময়সীমাতে এটি বিটম্যাপটি তৈরি করছে। 256.499 এ এটি তার প্রথম আউটপুট উত্পাদন করে যা বিটম্যাপ। যা এটির সর্বশেষ আউটপুট, কারণ এটি কেবল একটি একক আউটপুট উত্পাদন করে - একক সম্পূর্ণ বিটম্যাপ।
jjanes
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.