স্পষ্টতই একই ফলাফল পাওয়ার বিভিন্ন উপায় রয়েছে, আপনার প্রশ্নটি মনে হয় মাইএসকিউএলে প্রতিটি গ্রুপে শেষ ফলাফল পাওয়ার কার্যকর উপায় কোনটি। আপনি যদি প্রচুর পরিমাণে ডেটা নিয়ে কাজ করছেন এবং ধরে নিচ্ছেন যে আপনি মাইএসকিউএল এর সর্বশেষতম সংস্করণ (যেমন 5..7.২১ এবং ৮.০.৪-আরসি) সহ ইনোডিবি ব্যবহার করছেন তবে এটি করার কোনও কার্যকর উপায় নাও থাকতে পারে।
আমাদের মাঝে মাঝে 60 মিলিয়নেরও বেশি সারি সহ টেবিলগুলি দিয়ে এটি করা দরকার।
এই উদাহরণগুলির জন্য আমি প্রায় 1.5 মিলিয়ন সারি সহ ডেটা ব্যবহার করব যেখানে কোয়েরিতে ডেটাতে সমস্ত গোষ্ঠীর জন্য ফলাফলগুলি খুঁজে পাওয়া দরকার। আমাদের প্রকৃত ক্ষেত্রে আমাদের প্রায়শই প্রায় ২,০০০ গ্রুপ থেকে ডেটা ফিরিয়ে নেওয়া দরকার (যা অনুমানের সাথে খুব বেশি ডেটা পরীক্ষা করার প্রয়োজন হয় না)।
আমি নিম্নলিখিত সারণি ব্যবহার করব:
CREATE TABLE temperature(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
groupID INT UNSIGNED NOT NULL,
recordedTimestamp TIMESTAMP NOT NULL,
recordedValue INT NOT NULL,
INDEX groupIndex(groupID, recordedTimestamp),
PRIMARY KEY (id)
);
CREATE TEMPORARY TABLE selected_group(id INT UNSIGNED NOT NULL, PRIMARY KEY(id));
তাপমাত্রা টেবিলটি প্রায় 1.5 মিলিয়ন এলোমেলো রেকর্ড এবং 100 টি বিভিন্ন গোষ্ঠী সহ জনবহুল। নির্বাচিত_গোষ্ঠীটি এই 100 টি গ্রুপের সাথে জনবহুল (আমাদের ক্ষেত্রে এটি সাধারণত সমস্ত দলের জন্য 20% এর চেয়ে কম হবে)।
এই ডেটাটি এলোমেলো হওয়ার অর্থ এটির অর্থ হ'ল একাধিক সারিতে একই রেকর্ডড টাইমস্ট্যাম্প থাকতে পারে। আমরা যা চাই তা হ'ল প্রতিটি গ্রুপের জন্য শেষ রেকর্ডডটাইমস্ট্যাম্প সহ গ্রুপআইডির ক্রম অনুসারে নির্বাচিত সমস্ত গ্রুপের একটি তালিকা পাওয়া, এবং যদি একই গ্রুপের মতো একাধিক সারি সারি থাকে তবে সেই সারিগুলির শেষ ম্যাচিং আইডি।
যদি হাইপোথিটিক্যালি মাইএসকিউএলের একটি শেষ () ফাংশন থাকে যা একটি বিশেষ অর্ডার দ্বারা একটি বিশেষ আদেশের মাধ্যমে শেষ সারি থেকে মানগুলি ফিরিয়ে দেয় তবে আমরা কেবল এটি করতে পারি:
SELECT
last(t1.id) AS id,
t1.groupID,
last(t1.recordedTimestamp) AS recordedTimestamp,
last(t1.recordedValue) AS recordedValue
FROM selected_group g
INNER JOIN temperature t1 ON t1.groupID = g.id
ORDER BY t1.recordedTimestamp, t1.id
GROUP BY t1.groupID;
যা কেবলমাত্র এই ক্ষেত্রে কয়েকটি 100 টি সারি পরীক্ষা করতে হবে কারণ এটি কোনও সাধারণ গ্রুপের মাধ্যমে ফাংশন ব্যবহার করে না। এটি 0 সেকেন্ডে কার্যকর হবে এবং অতএব অত্যন্ত দক্ষ হবে। নোট করুন যে সাধারণত মাইএসকিউএলে আমরা একটি অর্ডার দ্বারা ধারাটি অনুসরণ করে গ্রুপের অনুচ্ছেদ অনুসারে দেখতে পাই তবে এই আদেশের মাধ্যমে ধারাটি শেষ () ফাংশনটির জন্য অর্ডার নির্ধারণ করতে ব্যবহৃত হয়, যদি এটি গ্রুপের পরে হয় তবে এটি গ্রুপের আদেশ দিবে। যদি কোনও গ্রুপ বাই ক্লজ উপস্থিত না থাকে তবে প্রত্যাবর্তিত সারিগুলির মধ্যে সর্বশেষ মানগুলি সমান হবে।
তবে মাইএসকিউএল এর এটি নেই তাই আসুন এটির কী রয়েছে তার বিভিন্ন ধারণাটি দেখুন এবং প্রমাণ করুন যে এগুলির কোনওটিই দক্ষ নয়।
উদাহরণ 1
SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM selected_group g
INNER JOIN temperature t1 ON t1.id = (
SELECT t2.id
FROM temperature t2
WHERE t2.groupID = g.id
ORDER BY t2.recordedTimestamp DESC, t2.id DESC
LIMIT 1
);
এটি 3,009,254 সারি পরীক্ষা করেছে এবং 5.7.21 এ 85 0.859 সেকেন্ড সময় নিয়েছে এবং 8.0.4-আর সি তে সামান্য লম্বা হয়েছে
উদাহরণ 2
SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM temperature t1
INNER JOIN (
SELECT max(t2.id) AS id
FROM temperature t2
INNER JOIN (
SELECT t3.groupID, max(t3.recordedTimestamp) AS recordedTimestamp
FROM selected_group g
INNER JOIN temperature t3 ON t3.groupID = g.id
GROUP BY t3.groupID
) t4 ON t4.groupID = t2.groupID AND t4.recordedTimestamp = t2.recordedTimestamp
GROUP BY t2.groupID
) t5 ON t5.id = t1.id;
এটি 1,505,331 সারি পরীক্ষা করেছে এবং 5.7.21 এ 25 1.25 সেকেন্ড নিয়েছে এবং 8.0.4-আরসি তে সামান্য দীর্ঘ
উদাহরণ 3
SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM temperature t1
WHERE t1.id IN (
SELECT max(t2.id) AS id
FROM temperature t2
INNER JOIN (
SELECT t3.groupID, max(t3.recordedTimestamp) AS recordedTimestamp
FROM selected_group g
INNER JOIN temperature t3 ON t3.groupID = g.id
GROUP BY t3.groupID
) t4 ON t4.groupID = t2.groupID AND t4.recordedTimestamp = t2.recordedTimestamp
GROUP BY t2.groupID
)
ORDER BY t1.groupID;
এটি 3,009,685 সারি পরীক্ষা করেছে এবং 5.7.21 এ 95 1.95 সেকেন্ড সময় নিয়েছে এবং 8.0.4-আর সি তে সামান্য লম্বা হয়েছে
উদাহরণ 4
SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM selected_group g
INNER JOIN temperature t1 ON t1.id = (
SELECT max(t2.id)
FROM temperature t2
WHERE t2.groupID = g.id AND t2.recordedTimestamp = (
SELECT max(t3.recordedTimestamp)
FROM temperature t3
WHERE t3.groupID = g.id
)
);
এটি 6,137,810 সারি পরীক্ষা করেছে এবং 5.7.21 এ ~ 2.2 সেকেন্ড সময় নিয়েছে এবং 8.0.4-আরসি তে কিছুটা লম্বা করেছে
উদাহরণ 5
SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM (
SELECT
t2.id,
t2.groupID,
t2.recordedTimestamp,
t2.recordedValue,
row_number() OVER (
PARTITION BY t2.groupID ORDER BY t2.recordedTimestamp DESC, t2.id DESC
) AS rowNumber
FROM selected_group g
INNER JOIN temperature t2 ON t2.groupID = g.id
) t1 WHERE t1.rowNumber = 1;
এটি 6,017,808 সারি পরীক্ষা করেছে এবং 8.0.4-rc এ ~ 4.2 সেকেন্ড নিয়েছে
উদাহরণ 6
SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM (
SELECT
last_value(t2.id) OVER w AS id,
t2.groupID,
last_value(t2.recordedTimestamp) OVER w AS recordedTimestamp,
last_value(t2.recordedValue) OVER w AS recordedValue
FROM selected_group g
INNER JOIN temperature t2 ON t2.groupID = g.id
WINDOW w AS (
PARTITION BY t2.groupID
ORDER BY t2.recordedTimestamp, t2.id
RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
)
) t1
GROUP BY t1.groupID;
এটি 6,017,908 সারি পরীক্ষা করেছে এবং 8.0.4-rc এ 17.5 সেকেন্ড সময় নিয়েছে
উদাহরণ 7
SELECT t1.id, t1.groupID, t1.recordedTimestamp, t1.recordedValue
FROM selected_group g
INNER JOIN temperature t1 ON t1.groupID = g.id
LEFT JOIN temperature t2
ON t2.groupID = g.id
AND (
t2.recordedTimestamp > t1.recordedTimestamp
OR (t2.recordedTimestamp = t1.recordedTimestamp AND t2.id > t1.id)
)
WHERE t2.id IS NULL
ORDER BY t1.groupID;
এইটি চিরকালের জন্য নিচ্ছে তাই আমাকে এটি মেরে ফেলতে হয়েছিল।