যদিও আমি অন্যান্য মন্তব্যকারীদের সাথে একমত হয়েছি যে এটি একটি গণনামূলকভাবে ব্যয়বহুল সমস্যা, তবুও আমি মনে করি যে আপনি যে এসকিউএল ব্যবহার করছেন তা টুইট করে উন্নতির অনেক জায়গা রয়েছে। উদাহরণস্বরূপ, আমি 15 মিমি নাম এবং 3 কে বাক্যাংশ সহ একটি জাল তথ্য সেট তৈরি করেছি, পুরানো পদ্ধতির দৌড়েছি এবং একটি নতুন পদ্ধতির দৌড়েছি ran
একটি নকল ডেটা সেট তৈরি করতে নতুন স্ক্রিপ্ট এবং নতুন পদ্ধতির চেষ্টা করুন
টি এল; ডিআর
আমার মেশিনে এবং এই জাল ডেটা সেটটিতে, আসল পদ্ধতিটি চালাতে প্রায় 4 ঘন্টা সময় নেয় । প্রস্তাবিত নতুন পদ্ধতির জন্য প্রায় 10 মিনিট সময় লাগে , যথেষ্ট উন্নতি। প্রস্তাবিত পদ্ধতির সংক্ষিপ্তসার এখানে দেওয়া হল:
- প্রতিটি নামের জন্য অফসেটে প্রতিটি অক্ষর থেকে শুরু করে স্ট্রিং তৈরি করুন (এবং একটি অপ্টিমাইজেশন হিসাবে দীর্ঘতম খারাপ বাক্যাংশের দৈর্ঘ্যে আবৃত)
- এই সাবস্ট্রিংগুলিতে একটি ক্লাস্টার্ড সূচক তৈরি করুন
- প্রতিটি খারাপ বাক্যাংশের জন্য, কোনও ম্যাচ শনাক্ত করতে এই সাবস্ট্রিংগুলিতে একটি অনুসন্ধান করুন
- প্রতিটি আসল স্ট্রিংয়ের জন্য, সেই স্ট্রিংয়ের এক বা একাধিক সাবস্ট্রিংয়ের সাথে মেলে স্বতন্ত্র খারাপ বাক্যাংশের সংখ্যা গণনা করুন
আসল পদ্ধতির: অ্যালগরিদমিক বিশ্লেষণ
মূল UPDATE
বিবৃতিটির পরিকল্পনা থেকে , আমরা দেখতে পাচ্ছি যে কাজের পরিমাণ নামের সংখ্যার (15 মিমি) এবং বাক্যাংশের সংখ্যা (3 কে) উভয়ের ক্ষেত্রেই রৈখিকভাবে আনুপাতিক। সুতরাং আমরা যদি উভয় নাম এবং বাক্যাংশের সংখ্যা 10 দ্বারা এক করে করি তবে সামগ্রিক চলমান সময়টি 100 ডলার গতি হতে চলেছে।
কোয়েরিটি আসলে দৈর্ঘ্যের সমানুপাতিক name
; এটি ক্যোয়ারী পরিকল্পনায় কিছুটা গোপন থাকা সত্ত্বেও, টেবিলের স্পুলটি অনুসন্ধানের জন্য এটি "মৃত্যুদণ্ডের সংখ্যা" এর মধ্য দিয়ে আসে। আসল পরিকল্পনায়, আমরা দেখতে পাচ্ছি যে এটি প্রতি একবার নয় name
, তবে একবারে প্রতি চরিত্রের মধ্যে একবার অফসেট হয় name
। সুতরাং রান-টাইম জটিলতায় এই পদ্ধতিটি ও ( # names
* # phrases
* name length
)।
নতুন পদ্ধতির: কোড
এই কোডটি পুরো পেস্টবিনেও পাওয়া যায় তবে আমি সুবিধার জন্য এটি এখানে অনুলিপি করেছি। Pastebin এছাড়াও পূর্ণ পদ্ধতি সংজ্ঞা, যার মধ্যে রয়েছে @minId
এবং @maxId
ভেরিয়েবল যে আপনার নিচে দেখুন বর্তমান ব্যাচ সীমানা নির্ধারণ করতে।
-- For each name, generate the string at each offset
DECLARE @maxBadPhraseLen INT = (SELECT MAX(LEN(phrase)) FROM Bad_Phrase)
SELECT s.id, sub.sub_name
INTO #SubNames
FROM (SELECT * FROM SourceTable WHERE id BETWEEN @minId AND @maxId) s
CROSS APPLY (
-- Create a row for each substring of the name, starting at each character
-- offset within that string. For example, if the name is "abcd", this CROSS APPLY
-- will generate 4 rows, with values ("abcd"), ("bcd"), ("cd"), and ("d"). In order
-- for the name to be LIKE the bad phrase, the bad phrase must match the leading X
-- characters (where X is the length of the bad phrase) of at least one of these
-- substrings. This can be efficiently computed after indexing the substrings.
-- As an optimization, we only store @maxBadPhraseLen characters rather than
-- storing the full remainder of the name from each offset; all other characters are
-- simply extra space that isn't needed to determine whether a bad phrase matches.
SELECT TOP(LEN(s.name)) SUBSTRING(s.name, n.n, @maxBadPhraseLen) AS sub_name
FROM Numbers n
ORDER BY n.n
) sub
-- Create an index so that bad phrases can be quickly compared for a match
CREATE CLUSTERED INDEX IX_SubNames ON #SubNames (sub_name)
-- For each name, compute the number of distinct bad phrases that match
-- By "match", we mean that the a substring starting from one or more
-- character offsets of the overall name starts with the bad phrase
SELECT s.id, COUNT(DISTINCT b.phrase) AS bad_count
INTO #tempBadCounts
FROM dbo.Bad_Phrase b
JOIN #SubNames s
ON s.sub_name LIKE b.phrase + '%'
GROUP BY s.id
-- Perform the actual update into a "bad_count_new" field
-- For validation, we'll compare bad_count_new with the originally computed bad_count
UPDATE s
SET s.bad_count_new = COALESCE(b.bad_count, 0)
FROM dbo.SourceTable s
LEFT JOIN #tempBadCounts b
ON b.id = s.id
WHERE s.id BETWEEN @minId AND @maxId
নতুন পদ্ধতির: ক্যোয়ারী পরিকল্পনা
প্রথমত, আমরা প্রতিটি অক্ষর অফসেট থেকে শুরু করে স্ট্রিং তৈরি করি
তারপরে এই সাবস্ট্রিংগুলিতে একটি ক্লাস্টার্ড সূচক তৈরি করুন
এখন, প্রতিটি খারাপ বাক্যাংশের জন্য আমরা কোনও ম্যাচ শনাক্ত করার জন্য এই সাবস্ট্রাস্টিংগুলিতে অনুসন্ধান করি। তারপরে আমরা সেই স্ট্রিংয়ের এক বা একাধিক সাবস্ট্রিংয়ের সাথে মেলে স্বতন্ত্র খারাপ বাক্যগুলির সংখ্যা গণনা করি এটি সত্যিই মূল পদক্ষেপ; যেভাবে আমরা সাবস্ট্রিংগুলিকে সূচি দিয়েছি, সেই কারণে আমাদের আর খারাপ বাক্যাংশ এবং নামগুলির একটি সম্পূর্ণ ক্রস-পণ্য পরীক্ষা করতে হবে না। এই পদক্ষেপটি, যা প্রকৃত গণনা করে, প্রকৃত রান-টাইমের মাত্র 10% (বাকীটি সাবস্ট্রিংয়ের প্রাক প্রক্রিয়াজাতকরণ) for
শেষ অবধি, LEFT OUTER JOIN
কোনও খারাপ বাক্য খুঁজে পাওয়া যায়নি এমন কোনও নামের জন্য একটি 0 গণনা নির্ধারণ করতে একটি ব্যবহার করে প্রকৃত আপডেট বিবৃতিটি সম্পাদন করুন ।
নতুন পদ্ধতির: অ্যালগরিদমিক বিশ্লেষণ
নতুন পদ্ধতির দুটি ধাপে বিভক্ত করা যেতে পারে, প্রাক-প্রক্রিয়াজাতকরণ এবং ম্যাচিং। আসুন নিম্নলিখিত ভেরিয়েবলগুলি সংজ্ঞা দিন:
N
নাম #
B
= # খারাপ বাক্যাংশের
L
= গড় নামের দৈর্ঘ্য, অক্ষরে
প্রাক-প্রক্রিয়াজাতকরণের পর্বটি সাবস্ট্রিংগুলি O(N*L * LOG(N*L))
তৈরি করতে N*L
এবং তারপরে তাদেরকে বাছাই করার জন্য।
আসল O(B * LOG(N*L))
মিলটি প্রতিটি খারাপ বাক্যাংশের জন্য সাবস্ট্রিংগুলিতে সন্ধান করার জন্য।
এইভাবে, আমরা একটি অ্যালগরিদম তৈরি করেছি যা খারাপ বাক্যাংশের সংখ্যার সাথে রৈখিকভাবে স্কেল করে না, একটি মূল পারফরম্যান্স আনলক করার সাথে সাথে আমরা 3K বাক্য এবং এর বাইরেও স্কেল করি। অন্যভাবে বলা হয়েছে, 300 টি খারাপ শব্দগুচ্ছ থেকে 3 কে খারাপ বাক্যাংশে যাওয়ার জন্য মূল প্রয়োগটি প্রায় 10x লাগে takes আমরা যদি 3 কে খারাপ বাক্যাংশ থেকে 30 কে যেতে যাই তবে একইভাবে এটি আরও 10x সময় লাগবে। তবে নতুন বাস্তবায়নটি উপ-রৈখিকভাবে স্কেল করবে এবং 30K বাজে বাক্যাংশগুলিকে ছোট করে দিলে 3K খারাপ বাক্যাংশগুলিতে পরিমাপ করা সময়টি 2x এরও কম সময় নেয়।
অনুমান / গুহাত
- আমি সামগ্রিক কাজটি পরিমিত আকারের ব্যাচগুলিতে ভাগ করছি। এটি উভয় পদ্ধতির জন্য সম্ভবত এটি একটি ভাল ধারণা, তবে নতুন পদ্ধতির জন্য এটি বিশেষত গুরুত্বপূর্ণ যাতে
SORT
সাবস্ট্রিংগুলি প্রতিটি ব্যাচের জন্য স্বতন্ত্র এবং স্মৃতিতে সহজেই ফিট করে। আপনি প্রয়োজন হিসাবে ব্যাচের আকারটি পরিচালনা করতে পারেন তবে সমস্ত ব্যাগের 15 মিমি সারি চেষ্টা করা বুদ্ধিমানের কাজ হবে না।
- আমি এসকিউএল ২০১৪-তে আছি, এসকিউএল 2005 নয়, যেহেতু আমার এসকিউএল 2005 মেশিনে অ্যাক্সেস নেই। এসকিউএল 2005-এ উপলব্ধ না এমন কোনও সিনট্যাক্স ব্যবহার না করার বিষয়ে আমি সতর্কতা অবলম্বন করেছি, তবে এসকিউএল 2012+ তে টেম্পডবিটি অলস লেখার বৈশিষ্ট্য এবং এসকিউএল ২০১৪ এর সমান্তরাল নির্বাচন অন্তর্ভুক্তি থেকে আমি কোনও সুবিধা পাচ্ছি ।
- নাম এবং বাক্যাংশ উভয়ের দৈর্ঘ্য নতুন পদ্ধতির পক্ষে মোটামুটি গুরুত্বপূর্ণ। আমি ধরে নিচ্ছি যে খারাপ বাক্যাংশগুলি সাধারণত মোটামুটি ছোট হয় কারণ এটি বাস্তব-বিশ্বের ব্যবহারের ক্ষেত্রে মেলে match নামগুলি খারাপ বাক্যগুলির তুলনায় বেশ খানিকটা দীর্ঘ, তবে ধরে নেওয়া হয় হাজার হাজার অক্ষর নয়। আমি মনে করি এটি একটি ন্যায্য ধারণা, এবং দীর্ঘ নামের স্ট্রিংগুলি আপনার মূল পদ্ধতির পাশাপাশি ধীর করে দেবে।
- উন্নয়নের কিছু অংশ (তবে এর সবের কাছাকাছি কোথাও নেই) এই কারণে যে নতুন পদ্ধতির সমান্তরালতাকে পুরাতন পদ্ধতির (যা একক থ্রেডযুক্ত চালিত) এর চেয়ে বেশি কার্যকরভাবে লাভ করতে পারে to আমি একটি কোয়াড কোর ল্যাপটপে আছি, সুতরাং এই কোরগুলি ব্যবহার করতে পারে এমন পদ্ধতির সাথে ভাল লাগছে।
সম্পর্কিত ব্লগ পোস্ট
অ্যারন বার্ট্র্যান্ড তার ব্লগ পোস্টে এই ধরণের সমাধানটি আরও বিশদে অনুসন্ধান করে একটি সূচক পেতে একটি উপায় যার মাধ্যমে নেতৃস্থানীয়% ওয়াইল্ডকার্ড অনুসন্ধান করা যায় ।