উত্তর:
সরল থেকে ফাঁক পর্যন্ত ফাঁক দিয়ে অ-ইউনিফর্ম পর্যন্ত বেশ কয়েকটি কেস পরিচালনা করার একটি দুর্দান্ত পোস্ট।
http://jan.kneschke.de/projects/mysql/order-by-rand/
বেশিরভাগ সাধারণ ক্ষেত্রে, আপনি এটি কীভাবে করবেন তা এখানে:
SELECT name
FROM random AS r1 JOIN
(SELECT CEIL(RAND() *
(SELECT MAX(id)
FROM random)) AS id)
AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 1
এটি ধরে নিয়েছে যে আইডির বিতরণ সমান এবং আইডি তালিকার মধ্যে ফাঁকও থাকতে পারে। আরও উন্নত উদাহরণের জন্য নিবন্ধটি দেখুন
mysqli_fetch_assoc($result)
? বা এই 10 ফলাফলগুলি অগত্যা আলাদা করা যায় না?
SELECT column FROM table
ORDER BY RAND()
LIMIT 10
দক্ষ সমাধান নয় তবে কাজ করে
ORDER BY RAND()
তুলনামূলকভাবে ধীর
SELECT words, transcription, translation, sound FROM vocabulary WHERE menu_id=$menuId ORDER BY RAND() LIMIT 10
প্লেস, 0.0010 লাগে, লিমিটেড 10 ছাড়াই এটি 0.0012 নিয়েছে (সেই টেবিলটিতে 3500 শব্দ রয়েছে)।
সাধারণ ক্যোয়ারী যা দুর্দান্ত পারফরম্যান্স করে এবং ফাঁক দিয়ে কাজ করে :
SELECT * FROM tbl AS t1 JOIN (SELECT id FROM tbl ORDER BY RAND() LIMIT 10) as t2 ON t1.id=t2.id
200 কে টেবিলের এই ক্যোয়ারিতে 0.08 সেকেন্ড লাগে এবং সাধারণ সংস্করণ (র্যান্ডের মাধ্যমে টিবিএল অর্ডার থেকে নির্বাচন করুন () সীমা 10) লাগে 0.35s আমার মেশিনে ।
এটি দ্রুত, কারণ সাজানোর ধাপটি কেবল ইনডেক্সড আইডি কলাম ব্যবহার করে। আপনি এই আচরণটি ব্যাখ্যাতে দেখতে পারেন:
* টিবিএল অর্ডার থেকে র্যান্ডের () সীমাবদ্ধ 10 নির্বাচন করুন:
টিবিএল থেকে টি 1 যোগ করুন হিসাবে নির্বাচন করুন (র্যান্ডের মাধ্যমে টিবিএল অর্ডার থেকে আইডি নির্বাচন করুন () লিমিটেড 10) টি 1 তে টি 2 এআইডি হিসাবে = t2.id
ওজনযুক্ত সংস্করণ : https://stackoverflow.com/a/41577458/893432
আমি একটি ধীর সিপিইউ দিয়ে দ্রুত জিজ্ঞাসা (প্রায় 0.5 সেকেন্ড) পাচ্ছি , 400 কে রেজিস্ট্রেশন করা মাইএসকিউএল ডাটাবেস নন-ক্যাশেড 2 জিবি আকারে 10 এলোমেলো সারি নির্বাচন করছি। এখানে আমার কোড দেখুন: মাইএসকিউএল এলোমেলো সারিগুলির দ্রুত নির্বাচন
<?php
$time= microtime_float();
$sql='SELECT COUNT(*) FROM pages';
$rquery= BD_Ejecutar($sql);
list($num_records)=mysql_fetch_row($rquery);
mysql_free_result($rquery);
$sql="SELECT id FROM pages WHERE RAND()*$num_records<20
ORDER BY RAND() LIMIT 0,10";
$rquery= BD_Ejecutar($sql);
while(list($id)=mysql_fetch_row($rquery)){
if($id_in) $id_in.=",$id";
else $id_in="$id";
}
mysql_free_result($rquery);
$sql="SELECT id,url FROM pages WHERE id IN($id_in)";
$rquery= BD_Ejecutar($sql);
while(list($id,$url)=mysql_fetch_row($rquery)){
logger("$id, $url",1);
}
mysql_free_result($rquery);
$time= microtime_float()-$time;
logger("num_records=$num_records",1);
logger("$id_in",1);
logger("Time elapsed: <b>$time segundos</b>",1);
?>
ORDER BY RAND()
FLUSH STATUS; SELECT ...; SHOW SESSION STATUS LIKE 'Handler%';
এটি দেখতে ব্যবহার করুন ।
ORDER BY RAND()
হ'ল এটি কেবল আইডির (সম্পূর্ণ সারি নয়) বাছাই করে, তাই টেম্প টেবিলটি আরও ছোট, তবে এখনও তাদের সমস্তকে বাছাই করতে হবে।
এটি খুব সাধারণ এবং একক লাইন ক্যোয়ারী।
SELECT * FROM Table_Name ORDER BY RAND() LIMIT 0,10;
order by rand()
টেবিলটি বড় হলে খুব ধীর
বই থেকে:
একটি অফসেট ব্যবহার করে একটি এলোমেলো সারি চয়ন করুন
পূর্ববর্তী বিকল্পগুলির মধ্যে পাওয়া সমস্যাগুলি এড়ানোর জন্য আরেকটি কৌশল হ'ল ডেটা সেটে সারিগুলি গণনা করা এবং 0 এবং গণনার মধ্যে একটি এলোমেলো সংখ্যা ফিরে পাওয়া। তারপরে ডেটা সেটটি জিজ্ঞাসা করার সময় এই নম্বরটি অফসেট হিসাবে ব্যবহার করুন
<?php
$rand = "SELECT ROUND(RAND() * (SELECT COUNT(*) FROM Bugs))";
$offset = $pdo->query($rand)->fetch(PDO::FETCH_ASSOC);
$sql = "SELECT * FROM Bugs LIMIT 1 OFFSET :offset";
$stmt = $pdo->prepare($sql);
$stmt->execute( $offset );
$rand_bug = $stmt->fetch();
এই সমাধানটি ব্যবহার করুন যখন আপনি সংক্ষিপ্ত মূল মানগুলি ধরে নিতে পারবেন না এবং আপনার প্রতিটি সারিটিতে নির্বাচিত হওয়ার এমনকি সম্ভাবনা রয়েছে তা নিশ্চিত করতে হবে।
SELECT count(*)
ধীর হয়ে যায়।
কোনও টেবিল থেকে এলোমেলো সারিগুলি কীভাবে নির্বাচন করবেন:
এখান থেকে: মাইএসকিউএলে এলোমেলো সারি নির্বাচন করুন
"টেবিল স্ক্যান" এর থেকে দ্রুত উন্নতি হ'ল র্যান্ডম আইডিগুলি তুলতে সূচি ব্যবহার করা।
SELECT *
FROM random, (
SELECT id AS sid
FROM random
ORDER BY RAND( )
LIMIT 10
) tmp
WHERE random.id = tmp.sid;
PRIMARY KEY
)।
ভাল যদি আপনার কীগুলিতে কোনও ফাঁক না থাকে এবং সেগুলি সমস্ত সংখ্যাসূচক হয় তবে আপনি এলোমেলো সংখ্যা গণনা করতে পারেন এবং সেই লাইনগুলি নির্বাচন করতে পারেন। তবে সম্ভবত এটি হবে না।
সুতরাং একটি সমাধান নিম্নলিখিত হবে:
SELECT * FROM table WHERE key >= FLOOR(RAND()*MAX(id)) LIMIT 1
যা মূলত নিশ্চিত করবে যে আপনি আপনার কীগুলির পরিসীমাটিতে একটি এলোমেলো নম্বর পেয়েছেন এবং তারপরে আপনি পরবর্তী সেরাটি আরও বড় চয়ন করুন। আপনার এটি 10 বার করতে হবে।
তবে এটি সত্যই এলোমেলো নয় কারণ সম্ভবত আপনার কীগুলি সমানভাবে বিতরণ করা হবে না।
এটি সত্যিই একটি বড় সমস্যা এবং সমস্ত প্রয়োজনীয়তা পূরণের সমাধান করা সহজ নয়, মাইএসকিউএল এর র্যান্ড () আপনি যদি সত্যিই 10 টি এলোমেলো সারি চান তবে আপনি সবচেয়ে ভাল পেতে পারেন is
তবে আরও একটি সমাধান রয়েছে যা দ্রুত, তবে এটি এলোমেলোভাবে আসে যখন একটি বাণিজ্য বন্ধ থাকে, তবে এটি আপনাকে আরও ভাল মানায়। এটি সম্পর্কে এখানে পড়ুন: আমি কীভাবে মাইএসকিউএল এর অর্ডার বাই র্যান্ড () ফাংশনটি অনুকূল করতে পারি?
প্রশ্নটি আপনার এলোমেলোভাবে হওয়া দরকার।
আপনি কি আরও কিছু ব্যাখ্যা করতে পারেন যাতে আমি আপনাকে একটি ভাল সমাধান দিতে পারি।
উদাহরণস্বরূপ, আমি যে সংস্থার সাথে কাজ করেছি তার একটি সমাধান ছিল যেখানে তাদের অত্যন্ত নিখুঁত এলোমেলো প্রয়োজন। তারা এলোমেলো মানগুলির সাথে ডেটাবেস প্রাক-পপুলেটিংয়ের সাথে শেষ হয়েছিল যা অবতরণী নির্বাচিত হয়েছিল এবং পরে আবার বিভিন্ন এলোমেলো মানগুলিতে সেট করা হয়েছিল।
আপনি যদি কদাচিৎ আপডেট করেন তবে আপনি একটি ইনক্রিমেন্টিং আইডিও পূরণ করতে পারেন যাতে আপনার কোনও ফাঁক নেই এবং নির্বাচনের আগে এলোমেলো কীগুলি গণনা করতে পারেন ... এটি ব্যবহারের ক্ষেত্রে নির্ভর করে!
Id
এবং আপনার সমস্ত এলোমেলো প্রশ্নগুলি আপনাকে সেটিকে ফিরিয়ে দেবে Id
।
FLOOR(RAND()*MAX(id))
বৃহত্তর আইডিস ফেরতের দিকে পক্ষপাতদুষ্ট।
বরং একটি বৃহত টেবিল থেকে প্রচুর এলোমেলো সারি ফিরতে আমার একটি প্রশ্নের প্রয়োজন ছিল query এটিই আমি নিয়ে এসেছি। প্রথমে সর্বোচ্চ রেকর্ড আইডি পান:
SELECT MAX(id) FROM table_name;
তারপরে সেই মানটির পরিবর্তে:
SELECT * FROM table_name WHERE id > FLOOR(RAND() * max) LIMIT n;
সারণীতে সর্বাধিক সর্বাধিক রেকর্ড আইডি এবং n আপনার ফলাফলের সেটে আপনি যে সারিটি চান তার সংখ্যা। ধারণাটি হ'ল রেকর্ড আইডিতে কোনও ফাঁক নেই যদিও আমি সন্দেহ করি যে এটি ফলাফলের উপর প্রভাব ফেলবে যদি থাকে (যদিও এটি চেষ্টা না করে)। আমি আরও জেনেরিক হওয়ার জন্য এই সঞ্চিত পদ্ধতিটি তৈরি করেছি; সারণির নাম এবং সারিগুলির নম্বরটি পাস করতে হবে। আমি উইন্ডোজ ২০০৮, ৩২ জিবি, দ্বৈত 3GHz E5450 এবং মাইএসকিউএল 5.5.38 চালিয়ে চলেছি এবং ১,,৩61১,২ .৪ সারি সহ একটি টেবিলের সাথে এটি ১,০০,০০০ সারি ফিরে পাওয়ার জন্য 0 .03 সেকেন্ড / ~ 11 সেকেন্ডে মোটামুটি সামঞ্জস্যপূর্ণ। (সময়গুলি মাইএসকিউএল ওয়ার্কবেঞ্চ 6.১ এর; আপনি নিজের পছন্দ অনুসারে ২ য় নির্বাচনী বিবৃতিতে ফ্লোরের পরিবর্তে সিইআইএলও ব্যবহার করতে পারেন)
DELIMITER $$
USE [schema name] $$
DROP PROCEDURE IF EXISTS `random_rows` $$
CREATE PROCEDURE `random_rows`(IN tab_name VARCHAR(64), IN num_rows INT)
BEGIN
SET @t = CONCAT('SET @max=(SELECT MAX(id) FROM ',tab_name,')');
PREPARE stmt FROM @t;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @t = CONCAT(
'SELECT * FROM ',
tab_name,
' WHERE id>FLOOR(RAND()*@max) LIMIT ',
num_rows);
PREPARE stmt FROM @t;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
$$
তারপর
CALL [schema name].random_rows([table name], n);
@ রিডসিওর উত্তরটি আমি উন্নত করেছি। এটি সবচেয়ে কার্যকর ক্যোয়ারী যা আমি ফাঁকাগুলির সাথে একটি বৃহত, সমানভাবে বিতরণ করা টেবিলটিতে খুঁজে পেতে পারি (>> ২.6 বি সারি রয়েছে এমন একটি টেবিল থেকে ১০০০ এলোমেলো সারি পাওয়ার পরীক্ষিত)।
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max := (SELECT MAX(id) FROM table)) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1)
যা চলছে তা আমাকে আনপ্যাক করুন।
@max := (SELECT MAX(id) FROM table)
MAX(id)
প্রতিবার যখন আপনার একটি সারির প্রয়োজন হয় তখন গণনার জন্য সামান্য ওভারহেড থাকেSELECT FLOOR(rand() * @max) + 1 as rand)
SELECT id FROM table INNER JOIN (...) on id > rand LIMIT 1
ইউনিয়নটি আপনাকে 1 টি ক্যোয়ারিতে সমস্ত কিছু ফিট করতে সহায়তা করে যাতে আপনি একাধিক ক্যোয়ারী করা এড়াতে পারেন। এটি আপনাকে গণনার ওভারহেড সংরক্ষণ করতে দেয়MAX(id)
। আপনার অ্যাপ্লিকেশন উপর নির্ভর করে, এটি অনেক বা খুব সামান্য ব্যাপার হতে পারে।
নোট করুন যে এটি কেবল আইডিগুলি পায় এবং এলোমেলো ক্রমে সেগুলি পায়। আপনি আরও উন্নত কিছু করতে চাইলে আমি আপনাকে এটি করার পরামর্শ দিই:
SELECT t.id, t.name -- etc, etc
FROM table t
INNER JOIN (
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max := (SELECT MAX(id) FROM table)) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1) UNION
(SELECT id FROM table INNER JOIN (SELECT FLOOR(RAND() * @max) + 1 as rand) r on id > rand LIMIT 1)
) x ON x.id = t.id
ORDER BY t.id
LIMIT 1
LIMIT 30
LIMIT 1
আপনাকে LIMIT 30
টেবিলের এলোমেলো পয়েন্ট থেকে পরপর 30 টি রেকর্ড পেতে পারে । পরিবর্তে (SELECT id FROM ....
মাঝখানে অংশটির 30 টি কপি থাকা উচিত ।
Riedsio
উত্তরটি আরও দক্ষ বলে মনে হচ্ছে না । আমি পিএইচপি .0.০.২২ এবং মারিয়্যাডবি ব্যবহার করে পৃষ্ঠায় সেকেন্ডে ৫০০ সেকেন্ড হিটের সাথে সেন্টোস tried এ চেষ্টা করেছি, Riedsio
উত্তরের সাথে আমি পেয়েছি ৫০০ ++ এর বেশি সফল সাড়া, তারপরে আপনার উত্তরটি পেয়েছি।
আমি এই http://jan.kneschke.de/projects/mysql/order-by-rand/ ব্যবহার করেছি রিডসিও দ্বারা পোস্ট করা (আমি একটি সঞ্চিত পদ্ধতির ক্ষেত্রে ব্যবহার করেছি যা এক বা একাধিক এলোমেলো মানগুলি প্রত্যাবর্তন করে):
DROP TEMPORARY TABLE IF EXISTS rands;
CREATE TEMPORARY TABLE rands ( rand_id INT );
loop_me: LOOP
IF cnt < 1 THEN
LEAVE loop_me;
END IF;
INSERT INTO rands
SELECT r1.id
FROM random AS r1 JOIN
(SELECT (RAND() *
(SELECT MAX(id)
FROM random)) AS id)
AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 1;
SET cnt = cnt - 1;
END LOOP loop_me;
নিবন্ধে তিনি solves ফাঁক সমস্যা ঘটাচ্ছে আইডি মধ্যে না, তাই র্যান্ডম ফলাফল একটি টেবিল বজায় রাখার দ্বারা (ইত্যাদি ট্রিগার ব্যবহার ... নিবন্ধটি দেখুন); আমি টেবিলের সাথে আরও একটি কলাম যুক্ত করে সমস্যাটি সমাধান করছি, 1 থেকে শুরু করে মঞ্জুরিযুক্ত সংখ্যার সাথে জনসংখ্যাযুক্ত ( সম্পাদনা করুন: এই কলামটি রানটাইম সময়ে সাবকোয়ারি দ্বারা নির্মিত অস্থায়ী টেবিলটিতে যুক্ত হবে, এটি আপনার স্থায়ী টেবিলকে প্রভাবিত করবে না):
DROP TEMPORARY TABLE IF EXISTS rands;
CREATE TEMPORARY TABLE rands ( rand_id INT );
loop_me: LOOP
IF cnt < 1 THEN
LEAVE loop_me;
END IF;
SET @no_gaps_id := 0;
INSERT INTO rands
SELECT r1.id
FROM (SELECT id, @no_gaps_id := @no_gaps_id + 1 AS no_gaps_id FROM random) AS r1 JOIN
(SELECT (RAND() *
(SELECT COUNT(*)
FROM random)) AS id)
AS r2
WHERE r1.no_gaps_id >= r2.id
ORDER BY r1.no_gaps_id ASC
LIMIT 1;
SET cnt = cnt - 1;
END LOOP loop_me;
নিবন্ধে আমি দেখতে পাচ্ছি যে তিনি কোডটি অনুকূল করে তোলার জন্য অনেকটা চেষ্টা করেছেন; আমার পরিবর্তনগুলি পারফরম্যান্সে কতটা প্রভাব ফেলবে আমার / তেমন কোনও ধারণা নেই তবে আমার পক্ষে খুব ভাল কাজ করে।
@no_gaps_id
কোন সূচক ব্যবহার করা যেতে পারে, তাই যদি আপনি তাকান EXPLAIN
আপনার প্রশ্নের জন্য, আপনি Using filesort
এবং Using where
(INDEX ছাড়া) subqueries জন্য, মূল প্রশ্নের সাথে বিপরীতে।
এখানে একটি গেম চেঞ্জার যা অনেকের পক্ষে সহায়ক হতে পারে;
আমার কাছে 200k সারি সহ সারণী আইডির একটি টেবিল রয়েছে , আমাকে এন এলোমেলো সারি বাছাই করা দরকার , তাই আমি টেবিলের বৃহত্তম আইডির ভিত্তিতে এলোমেলো মান উত্পন্ন করতে পছন্দ করি, আমি দ্রুততম অপারেশনটি খুঁজে বের করতে এই স্ক্রিপ্টটি তৈরি করেছি:
logTime();
query("SELECT COUNT(id) FROM tbl");
logTime();
query("SELECT MAX(id) FROM tbl");
logTime();
query("SELECT id FROM tbl ORDER BY id DESC LIMIT 1");
logTime();
ফলাফলগুলি হ'ল:
36.8418693542479
এমএস0.241041183472
এমএস0.216960906982
এমএসএই ফলাফলগুলির ভিত্তিতে, অর্ডার ডেস্ক সর্বাধিক আইডি পাওয়ার জন্য দ্রুততম ক্রিয়াকলাপ,
এখানে আমার প্রশ্নের উত্তরটি দেওয়া হয়েছে:
SELECT GROUP_CONCAT(n SEPARATOR ',') g FROM (
SELECT FLOOR(RAND() * (
SELECT id FROM tbl ORDER BY id DESC LIMIT 1
)) n FROM tbl LIMIT 10) a
...
SELECT * FROM tbl WHERE id IN ($result);
এফওয়াইআই: 200 কে টেবিল থেকে 10 টি এলোমেলো সারি পেতে, আমার কাছে 1.78 এমএস লাগলো (পিএইচপি পাশের সমস্ত ক্রিয়াকলাপ সহ)
LIMIT
কিছুটা বাড়ানোর পরামর্শ দিন - আপনি সদৃশগুলি পেতে পারেন।
সমস্ত সেরা উত্তর ইতিমধ্যে পোস্ট করা হয়েছে (মূলত যারা লিঙ্কটি উল্লেখ করেছেন http://jan.kneschke.de/projects/mysql/order-by-rand/ )।
আমি আরেকটি গতি বাড়ানোর সম্ভাবনাটি চিহ্নিত করতে চাই - ক্যাশে করা । আপনার এলোমেলো সারি কেন দরকার তা ভেবে দেখুন। সম্ভবত আপনি কোনও ওয়েবসাইটে কিছু এলোমেলো পোস্ট বা এলোমেলো বিজ্ঞাপন প্রদর্শন করতে চান। আপনি যদি 100 রেক / সেকেন্ড পাচ্ছেন, তবে কি প্রতিটি দর্শকের এলোমেলো সারি পাওয়া দরকার? সাধারণত এই এক্স এলোমেলো সারিগুলিকে 1 সেকেন্ডের জন্য (বা এমনকি 10 সেকেন্ড) ক্যাশে করা পুরোপুরি ঠিক। একই 1 সেকেন্ডের 100 জন অনন্য দর্শক একই র্যান্ডম পোস্টগুলি পান কিনা তা বিবেচ্য নয়, কারণ পরের দ্বিতীয় দ্বিতীয় 100 জন দর্শক বিভিন্ন সেট পোস্ট পাবেন।
এই ক্যাচিংটি ব্যবহার করার সময় আপনি এলোমেলো তথ্য পাওয়ার জন্য কিছু ধীর সমাধানও ব্যবহার করতে পারেন কারণ এটি আপনার রেকর্ড / সেকেন্ড নির্বিশেষে প্রতি সেকেন্ডে একবারে মাইএসকিউএল থেকে নেওয়া হবে।
এটি সুপার দ্রুত এবং আপনার শূন্যস্থান থাকলেও এটি 100% এলোমেলো।
x
আপনার উপলব্ধ সারিগুলির সংখ্যা গণনা করুনSELECT COUNT(*) as rows FROM TABLE
a_1,a_2,...,a_10
0 এবং এর মধ্যে 10 স্বতন্ত্র এলোমেলো সংখ্যা চয়ন করুনx
SELECT * FROM TABLE LIMIT 1 offset a_i
i = 1, ..., 10 এর জন্যআমি বই এই হ্যাক পাওয়া এসকিউএল Antipatterns থেকে বিল Karwin ।
SELECT column FROM table ORDER BY RAND() LIMIT 10
দ্রবণটি ও (1) এ থাকে যেখানে সমাধানটি ও (এনলগ (এন)) এ থাকে। হ্যাঁ, এটি দ্রুত সমাধান এবং এটি কোনও আইডির বিতরণের জন্য কাজ করে।
x
। আমি যুক্তি দিয়ে বলব যে এটি 10 টি সারির এলোমেলো প্রজন্ম নয়। আমার উত্তরে, আপনাকে তিনবার 10 বার ধাপে ক্যোরিটি চালাতে হবে, অর্থাত্ মৃত্যুদণ্ডপ্রাপ্তির জন্য কেবল একটি সারি পাওয়া যায় এবং যদি টেবিলের শেষে অফসেটটি থাকে তবে চিন্তার দরকার নেই।
একটি অস্থায়ী টেবিলের সাহায্যে @redsio এর উত্তরটি একত্রিত করুন (600 কে তেমন কিছু নয়):
DROP TEMPORARY TABLE IF EXISTS tmp_randorder;
CREATE TABLE tmp_randorder (id int(11) not null auto_increment primary key, data_id int(11));
INSERT INTO tmp_randorder (data_id) select id from datatable;
এবং তারপরে @redsios উত্তরটির একটি সংস্করণ নিন:
SELECT dt.*
FROM
(SELECT (RAND() *
(SELECT MAX(id)
FROM tmp_randorder)) AS id)
AS rnd
INNER JOIN tmp_randorder rndo on rndo.id between rnd.id - 10 and rnd.id + 10
INNER JOIN datatable AS dt on dt.id = rndo.data_id
ORDER BY abs(rndo.id - rnd.id)
LIMIT 1;
টেবিলটি বড় হলে, আপনি প্রথম অংশে ছাঁটাই করতে পারেন:
INSERT INTO tmp_randorder (data_id) select id from datatable where rand() < 0.01;
সংস্করণ: আপনি টেবিলটি tmp_randorder
অবিচলিত রাখতে পারতেন , এটিকে ডেটেটেবল_আইডলিস্ট বলে। নির্দিষ্ট ব্যবধানে (দিন, ঘন্টা) সেই টেবিলটি পুনরায় তৈরি করুন, যেহেতু এটিও গর্ত পাবে। যদি আপনার টেবিলটি সত্যিই বড় হয়ে যায় তবে আপনি গর্তগুলি আবারও পূরণ করতে পারেন
dt.id = l.data_id যেখানে ডেট.আইডি নাল, সেখানে ডেটাটেবল ডিটি যোগ করুন ডেটাটেবল_আইডিলিস্ট থেকে সম্পূর্ণ l.data_id নির্বাচন করুন;
সংস্করণ: আপনার ডেটাসেটটি সরাসরি ডেটেবলে বা অবিচ্ছিন্ন অতিরিক্ত টেবিলটিতে একটি এলোমেলো_সোর্টার কলাম দিন datatable_sortorder
। সেই কলামটি সূচক করে। আপনার অ্যাপ্লিকেশনটিতে একটি র্যান্ডম-মান তৈরি করুন (আমি এটি কল করব $rand
)।
select l.*
from datatable l
order by abs(random_sortorder - $rand) desc
limit 1;
এই সমাধানটি 'প্রান্ত সারিগুলিকে' সর্বোচ্চ এবং সর্বনিম্ন এলোমেলো_সোর্টর্ডারের সাথে বৈষম্যযুক্ত করে তাই তাদের বিরতিগুলিতে পুনরায় সাজান (দিনে একবার)।
আর একটি সহজ সমাধান হ'ল সারিগুলি র্যাঙ্কিং করবে এবং এগুলির মধ্যে একটি এলোমেলোভাবে আনবে এবং এই সমাধানের সাহায্যে আপনার টেবিলে কোনও 'আইডি' ভিত্তিক কলাম থাকতে হবে না।
SELECT d.* FROM (
SELECT t.*, @rownum := @rownum + 1 AS rank
FROM mytable AS t,
(SELECT @rownum := 0) AS r,
(SELECT @cnt := (SELECT RAND() * (SELECT COUNT(*) FROM mytable))) AS n
) d WHERE rank >= @cnt LIMIT 10;
আপনি যতটা সারি সন্ধান করতে চান সে হিসাবে আপনার প্রয়োজন অনুসারে সীমা মান পরিবর্তন করতে পারেন তবে এটি বেশিরভাগ ধারাবাহিক মান হতে পারে।
তবে, আপনি যদি ধারাবাহিক এলোমেলো মান না চান তবে আপনি একটি বড় নমুনা আনতে এবং এ থেকে এলোমেলোভাবে নির্বাচন করতে পারেন। কিছুটা এইরকম ...
SELECT * FROM (
SELECT d.* FROM (
SELECT c.*, @rownum := @rownum + 1 AS rank
FROM buildbrain.`commits` AS c,
(SELECT @rownum := 0) AS r,
(SELECT @cnt := (SELECT RAND() * (SELECT COUNT(*) FROM buildbrain.`commits`))) AS rnd
) d
WHERE rank >= @cnt LIMIT 10000
) t ORDER BY RAND() LIMIT 10;
একটি অটোজেনারেটেড আইডি থাকলে আমি বেশ ভাল দেখতে পাই যে মডুলো অপারেটর '%' ব্যবহার করা। উদাহরণস্বরূপ, যদি আপনার ,000০,০০০ এর বাইরে ১০,০০০ এলোমেলো রেকর্ডের প্রয়োজন হয় তবে আপনি প্রতি ows টি সারির মধ্যে ১ টি দরকার বলে এইটিকে সহজ করতে পারেন। এই ক্যোয়ারিতে এটি সরল করা যেতে পারে:
SELECT * FROM
table
WHERE
id %
FLOOR(
(SELECT count(1) FROM table)
/ 10000
) = 0;
লক্ষ্যমাত্রার সারিগুলিকে মোট উপলব্ধ হিসাবে ভাগ করার ফলাফল যদি কোনও পূর্ণসংখ্যক না হয়, আপনি যা চেয়েছিলেন তার চেয়ে আপনার কিছু অতিরিক্ত সারি থাকবে, সুতরাং ফলস্বরূপ সেটটি ছাঁটাতে আপনাকে এমন একটি সীমাবদ্ধ ধারা যুক্ত করা উচিত:
SELECT * FROM
table
WHERE
id %
FLOOR(
(SELECT count(1) FROM table)
/ 10000
) = 0
LIMIT 10000;
এটির জন্য একটি পূর্ণ স্ক্যানের প্রয়োজন, তবে এটি র্যান্ডের অর্ডার থেকে দ্রুত এবং আমার মতে এই থ্রেডে উল্লিখিত অন্যান্য বিকল্পগুলির চেয়ে বোঝা সহজ। এছাড়াও ডিবিতে লেখা সিস্টেমটি যদি ব্যাচগুলিতে সারিগুলির সেট তৈরি করে তবে আপনি যেখানে আশা করছেন তেমন এলোমেলো ফলাফল নাও পেতে পারেন।
আপনি যদি একটি এলোমেলো রেকর্ড চান (আইডির মধ্যে ফাঁক রয়েছে কিনা তা):
PREPARE stmt FROM 'SELECT * FROM `table_name` LIMIT 1 OFFSET ?';
SET @count = (SELECT
FLOOR(RAND() * COUNT(*))
FROM `table_name`);
EXECUTE stmt USING @count;
আমি সমস্ত উত্তর দেখেছি এবং আমি মনে করি না যে কেউ এই সম্ভাবনার কথা মোটেও উল্লেখ করেছেন এবং কেন তা নিশ্চিত নন।
আপনি যদি সামান্য ব্যয় করে অত্যন্ত সরলতা এবং গতি চান, তবে আমার কাছে মনে হয় ডিবিতে প্রতিটি সারির বিপরীতে একটি এলোমেলো সংখ্যার সংরক্ষণ করা বুদ্ধিমান। কেবল একটি অতিরিক্ত কলাম তৈরি করুন random_number
, এবং এটির ডিফল্ট সেট করুন RAND()
। এই কলামে একটি সূচক তৈরি করুন।
তারপরে আপনি যখন একটি সারিটি পুনরুদ্ধার করতে চান তখন আপনার কোডে একটি এলোমেলো সংখ্যা তৈরি করুন (পিএইচপি, পার্ল, যাই হোক না কেন) এবং এটি কলামের সাথে তুলনা করুন।
SELECT FROM tbl WHERE random_number >= :random LIMIT 1
আমার ধারণা, যদিও এটি একটি একক সারির জন্য খুব ঝরঝরে, ওপির মতো দশ সারি জিজ্ঞাসা করেছিল আপনাকে এটি আলাদা আলাদা দশবার কল করতে হবে (বা আমাকে সঙ্গে সঙ্গে পালিয়ে যাওয়ার মতো একটি চতুর ঝাঁকুনি দিয়ে আসবে)
নিম্নলিখিতটি আইডি কলামের চেয়ে দ্রুত, নিরপেক্ষ এবং স্বতন্ত্র হওয়া উচিত। তবে এটি গ্যারান্টি দেয় না যে প্রত্যাবর্তিত সারিগুলির সংখ্যার সাথে প্রত্যাবর্তন করা সারিগুলির সংখ্যা মেলে।
SELECT *
FROM t
WHERE RAND() < (SELECT 10 / COUNT(*) FROM t)
ব্যাখ্যা: ধরে নিচ্ছি আপনি ১০০ টির মধ্যে ১০ টি সারি চান তবে প্রতিটি সারিতে SELECTed হওয়ার সম্ভাবনা রয়েছে যা দ্বারা অর্জন করা যেতে পারে WHERE RAND() < 0.1
। এই পদ্ধতির 10 টি সারি গ্যারান্টি দেয় না; তবে যদি ক্যোয়ারী যথেষ্ট সময় চালানো হয় তবে নির্বাহের জন্য প্রতি সারির গড় সংখ্যা 10 এর কাছাকাছি হবে এবং টেবিলের প্রতিটি সারি সমানভাবে নির্বাচন করা হবে।
PREPARE stm from 'select * from table limit 10 offset ?';
SET @total = (select count(*) from table);
SET @_offset = FLOOR(RAND() * @total);
EXECUTE stm using @_offset;
আপনি এমন একটি ক্লজও প্রয়োগ করতে পারেন
PREPARE stm from 'select * from table where available=true limit 10 offset ?';
SET @total = (select count(*) from table where available=true);
SET @_offset = FLOOR(RAND() * @total);
EXECUTE stm using @_offset;
,000০০,০০০ সারি (M০০ এমবি) টেবিল ক্যোয়ারী এক্সিকিউশনটি পরীক্ষিত হয়েছে ~ 0.016 সেকেন্ড এইচডিডি ড্রাইভ
--EDIT--
অফসেটটি টেবিলের শেষের নিকটে একটি মান নিতে পারে, যার ফলে নির্বাচিত বিবৃতিটি কম সারিগুলি ফেরত দেবে (অথবা সম্ভবত কেবল 1 টি) সারি), এড়াতে আমরা offset
আবার এটি ঘোষণার পরে আবার পরীক্ষা করতে পারি
SET @rows_count = 10;
PREPARE stm from "select * from table where available=true limit ? offset ?";
SET @total = (select count(*) from table where available=true);
SET @_offset = FLOOR(RAND() * @total);
SET @_offset = (SELECT IF(@total-@_offset<@rows_count,@_offset-@rows_count,@_offset));
SET @_offset = (SELECT IF(@_offset<0,0,@_offset));
EXECUTE stm using @rows_count,@_offset;
আমি এই প্রশ্নটি ব্যবহার:
select floor(RAND() * (SELECT MAX(key) FROM table)) from table limit 10
প্রশ্নের সময়: 0.016 এস
আমি এটি এইভাবে করি:
select *
from table_with_600k_rows
where rand() < 10/600000
limit 10
আমি এটি পছন্দ করি কারণ অন্য টেবিলের প্রয়োজন হয় না, এটি লেখা সহজ, এবং এটি সম্পাদন করা খুব দ্রুত।
একটি টেবিল থেকে এলোমেলো তথ্য পেতে নীচের সহজ ক্যোয়ারী ব্যবহার করুন।
SELECT user_firstname ,
COUNT(DISTINCT usr_fk_id) cnt
FROM userdetails
GROUP BY usr_fk_id
ORDER BY cnt ASC
LIMIT 10
আমার ধারণা এটি সর্বোত্তম সম্ভাব্য উপায় ..
SELECT id, id * RAND( ) AS random_no, first_name, last_name
FROM user
ORDER BY random_no