মাইএসকিউএল 600K সারি থেকে 10 টি এলোমেলো সারিটি দ্রুত নির্বাচন করে


463

আমি কীভাবে সর্বোত্তম 600k থেকে এলোমেলোভাবে 10 সারি নির্বাচন করে এমন একটি ক্যোয়ারী লিখতে পারি?


15
এখানে 8 টি কৌশল ; সম্ভবত এক আপনার ক্ষেত্রে ভাল কাজ করবে।
রিক জেমস

উত্তর:


385

সরল থেকে ফাঁক পর্যন্ত ফাঁক দিয়ে অ-ইউনিফর্ম পর্যন্ত বেশ কয়েকটি কেস পরিচালনা করার একটি দুর্দান্ত পোস্ট।

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

এটি ধরে নিয়েছে যে আইডির বিতরণ সমান এবং আইডি তালিকার মধ্যে ফাঁকও থাকতে পারে। আরও উন্নত উদাহরণের জন্য নিবন্ধটি দেখুন


52
হ্যাঁ, যদি আপনার আইডিতে সম্ভাব্য বড় ব্যবধান থাকে তবে আপনার সর্বনিম্ন আইডি এলোমেলোভাবে বাছাইয়ের সম্ভাবনা আপনার উচ্চ আইডিগুলির তুলনায় অনেক কম। প্রকৃতপক্ষে সবচেয়ে বড় ব্যবধানটি বাছাইয়ের পরে প্রথম আইডি আসলে সবচেয়ে বেশি। সুতরাং এটি সংজ্ঞা দ্বারা এলোমেলো নয়।
lukeocodes

6
আপনি কীভাবে 10 টি বিভিন্ন এলোমেলো সারি পাবেন? আপনার কি 10 এর সীমা নির্ধারণ করতে হবে এবং তার সাথে 10 বার পুনরাবৃত্তি করতে হবে mysqli_fetch_assoc($result)? বা এই 10 ফলাফলগুলি অগত্যা আলাদা করা যায় না?
আদম

12
এলোমেলো মনে মনে যে কোনও ফলাফলের জন্য সমান সুযোগের প্রয়োজন। ;)
লুয়োকোডস

4
সম্পূর্ণ নিবন্ধটি অসম বিতরণ এবং বারবার ফলাফলের মতো বিষয়গুলিকে সম্বোধন করে।
ব্র্যাড্ড সোজনে

1
বিশেষত, আপনার আইডি শুরুর সময় যদি আপনার একটি ফাঁক থাকে তবে প্রথমটি সময়টির (মিনিট / সর্বাধিক-মিনিট) পেয়ে যাবে। সেক্ষেত্রে একটি সাধারণ ত্বক হ'ল MAX () - MIN () * RAND + MIN (), যা খুব ধীর নয়।
কোড অ্যাবমোনিটর 4

342
SELECT column FROM table
ORDER BY RAND()
LIMIT 10

দক্ষ সমাধান নয় তবে কাজ করে


139
ORDER BY RAND()তুলনামূলকভাবে ধীর
ম্যাটিউজ চারিটনিউক

7
ম্যাটিউজ - প্রুফ SELECT words, transcription, translation, sound FROM vocabulary WHERE menu_id=$menuId ORDER BY RAND() LIMIT 10প্লেস, 0.0010 লাগে, লিমিটেড 10 ছাড়াই এটি 0.0012 নিয়েছে (সেই টেবিলটিতে 3500 শব্দ রয়েছে)।
আর্থার কুশমান

26
@zeusakm 3500 শব্দগুলি তেমন কিছু নয়; সমস্যাটি হ'ল এটি একটি নির্দিষ্ট পয়েন্ট পেরিয়ে বিস্ফোরিত হয় কারণ মাইএসকিউএলকে প্রতিটি পড়ার পরে সমস্ত রেকর্ডটি বাছাই করতে হয়; এই অপারেশনটি হার্ড ডিস্কে একবার হিট করলে আপনি পার্থক্যটি অনুভব করতে পারেন।
জ্যাক

16
আমি আবার নিজেকে পুনরাবৃত্তি করতে চাই না, এটি পুরো টেবিল স্ক্যান। বড় টেবিলে এটি খুব সময় এবং মেমরি গ্রাস করে এবং এটি ডিস্কের অস্থায়ী টেবিলের ও অপারেশন তৈরির কারণ হতে পারে যা খুব ধীর।
ম্যাট

10
২০১০ সালে আমি যখন ফেসবুকের সাথে সাক্ষাত্কার দিচ্ছিলাম, তখন তারা আমাকে জিজ্ঞাসা করেছিল যে কীভাবে অজানা আকারের বিশাল ফাইল থেকে একটি র্যান্ডম রেকর্ড নির্বাচন করতে হয়, এক পড়তে। একবার আপনি একটি ধারণা নিয়ে আসেন, একাধিক রেকর্ড নির্বাচন করার জন্য এটি সাধারণকরণ করা সহজ। হ্যাঁ, পুরো ফাইলটি বাছাই করা হাস্যকর। একইসাথে, এটি খুব সুবিধাজনক। আমি এই পন্থাটি 1,000,000 + সারি সহ একটি টেবিল থেকে 10 টি এলোমেলো সারি বাছাই করতে ব্যবহার করেছি। অবশ্যই, আমাকে কিছুটা অপেক্ষা করতে হয়েছিল; তবে আমি কেবল একটি ধারণা পেতে চেয়েছিলাম, এই টেবিলের সাধারণ সারিগুলি কী দেখতে ...
osa

27

সাধারণ ক্যোয়ারী যা দুর্দান্ত পারফরম্যান্স করে এবং ফাঁক দিয়ে কাজ করে :

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


1
দুঃখিত, আমি পরীক্ষা! 600k রেকর্ডে ধীর পারফরম্যান্স।
ডিলান বি

@ ডিলানবি আমি একটি পরীক্ষার সাথে উত্তর আপডেট করেছি।
আলী

17

আমি একটি ধীর সিপিইউ দিয়ে দ্রুত জিজ্ঞাসা (প্রায় 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);
?>

11
আমার 14 মিলিয়নেরও বেশি রেকর্ড সারণী দেওয়া, এটি যতটা ধীরORDER BY RAND()
Fabrizio

5
@ স্নিপেটসফোড আপনার ক্ষেত্রে - 400k সারি আপনি সহজ "অর্ডার বাই র্যান্ড () ব্যবহার করতে পারেন।" 3 টি প্রশ্নের সাথে আপনার কৌশলটি অকেজো। আপনি এটিকে "আইডি নির্বাচন করুন, যেখানে পৃষ্ঠাগুলি থেকে
আইআরএল

4
আপনার কৌশলটি এখনও একটি টেবিল স্ক্যান করে। FLUSH STATUS; SELECT ...; SHOW SESSION STATUS LIKE 'Handler%';এটি দেখতে ব্যবহার করুন ।
রিক জেমস

4
200 কোষ / সেকেন্ডের ওয়েবপৃষ্ঠায় সেই প্রশ্নটি চালানোর চেষ্টা করুন। সংমেয় আপনাকে হত্যা করবে।
Marki555

@ রোমনপডলিনভের সমভূমিটির এই সুবিধাটি ORDER BY RAND()হ'ল এটি কেবল আইডির (সম্পূর্ণ সারি নয়) বাছাই করে, তাই টেম্প টেবিলটি আরও ছোট, তবে এখনও তাদের সমস্তকে বাছাই করতে হবে।
মার্কি 555

16

এটি খুব সাধারণ এবং একক লাইন ক্যোয়ারী।

SELECT * FROM Table_Name ORDER BY RAND() LIMIT 0,10;

20
এফওয়াইআই, order by rand()টেবিলটি বড় হলে খুব ধীর
রিকো

6
কখনও কখনও

ইনডেক্সিং বড় হলে টেবিলে প্রয়োগ করা উচিত।
মুহাম্মদ আজিম

1
সূচীকরণ এখানে সাহায্য করবে না। সূচকগুলি খুব নির্দিষ্ট জিনিসের জন্য সহায়ক এবং এই ক্যোয়ারি তাদের মধ্যে একটিও নয়।
অ্যান্ড্রু

13

বই থেকে:

একটি অফসেট ব্যবহার করে একটি এলোমেলো সারি চয়ন করুন

পূর্ববর্তী বিকল্পগুলির মধ্যে পাওয়া সমস্যাগুলি এড়ানোর জন্য আরেকটি কৌশল হ'ল ডেটা সেটে সারিগুলি গণনা করা এবং 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();

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


1
খুব বড় টেবিলের জন্য, SELECT count(*)ধীর হয়ে যায়।
হ্যান্স জেড

7

কোনও টেবিল থেকে এলোমেলো সারিগুলি কীভাবে নির্বাচন করবেন:

এখান থেকে: মাইএসকিউএলে এলোমেলো সারি নির্বাচন করুন

"টেবিল স্ক্যান" এর থেকে দ্রুত উন্নতি হ'ল র্যান্ডম আইডিগুলি তুলতে সূচি ব্যবহার করা।

SELECT *
FROM random, (
        SELECT id AS sid
        FROM random
        ORDER BY RAND( )
        LIMIT 10
    ) tmp
WHERE random.id = tmp.sid;

1
এটি মাইআইএসএএম-এর জন্য কিছু সহায়তা করে, তবে ইনোডিবি-র জন্য নয় (ধরে নিচ্ছেন আইডি ক্লাস্টারযুক্ত PRIMARY KEY)।
রিক জেমস

7

ভাল যদি আপনার কীগুলিতে কোনও ফাঁক না থাকে এবং সেগুলি সমস্ত সংখ্যাসূচক হয় তবে আপনি এলোমেলো সংখ্যা গণনা করতে পারেন এবং সেই লাইনগুলি নির্বাচন করতে পারেন। তবে সম্ভবত এটি হবে না।

সুতরাং একটি সমাধান নিম্নলিখিত হবে:

SELECT * FROM table WHERE key >= FLOOR(RAND()*MAX(id)) LIMIT 1

যা মূলত নিশ্চিত করবে যে আপনি আপনার কীগুলির পরিসীমাটিতে একটি এলোমেলো নম্বর পেয়েছেন এবং তারপরে আপনি পরবর্তী সেরাটি আরও বড় চয়ন করুন। আপনার এটি 10 ​​বার করতে হবে।

তবে এটি সত্যই এলোমেলো নয় কারণ সম্ভবত আপনার কীগুলি সমানভাবে বিতরণ করা হবে না।

এটি সত্যিই একটি বড় সমস্যা এবং সমস্ত প্রয়োজনীয়তা পূরণের সমাধান করা সহজ নয়, মাইএসকিউএল এর র‌্যান্ড () আপনি যদি সত্যিই 10 টি এলোমেলো সারি চান তবে আপনি সবচেয়ে ভাল পেতে পারেন is

তবে আরও একটি সমাধান রয়েছে যা দ্রুত, তবে এটি এলোমেলোভাবে আসে যখন একটি বাণিজ্য বন্ধ থাকে, তবে এটি আপনাকে আরও ভাল মানায়। এটি সম্পর্কে এখানে পড়ুন: আমি কীভাবে মাইএসকিউএল এর অর্ডার বাই র‌্যান্ড () ফাংশনটি অনুকূল করতে পারি?

প্রশ্নটি আপনার এলোমেলোভাবে হওয়া দরকার।

আপনি কি আরও কিছু ব্যাখ্যা করতে পারেন যাতে আমি আপনাকে একটি ভাল সমাধান দিতে পারি।

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

আপনি যদি কদাচিৎ আপডেট করেন তবে আপনি একটি ইনক্রিমেন্টিং আইডিও পূরণ করতে পারেন যাতে আপনার কোনও ফাঁক নেই এবং নির্বাচনের আগে এলোমেলো কীগুলি গণনা করতে পারেন ... এটি ব্যবহারের ক্ষেত্রে নির্ভর করে!


হাই হাই এই বিশেষ ক্ষেত্রে কীগুলির ফাঁকের অভাব হওয়া উচিত নয়, তবে সময়ের সাথে সাথে এটি পরিবর্তিত হতে পারে। এবং যখন আপনার উত্তরটি কাজ করে, এটি ক্রমাগত 10 টি সারি তৈরি করে (আমি সীমা লিখতে পারি 10) যা ক্রমাগত এবং আমি আরও কথা বলার জন্য এলোমেলোতা চেয়েছিলাম। :) ধন্যবাদ.
ফ্রান্সিস্ক

আপনার যদি 10 টির প্রয়োজন হয় তবে 10 টি অনন্য সারি তৈরি করতে কোনও রকম ইউনিয়ন ব্যবহার করুন।
জনো

আমি যা বলেছিলাম তা জানায়। আপনার এটি 10 ​​বার কার্যকর করা দরকার। এটিকে উইশিয়ান ইউনিয়নের সাথে একত্রিত করা এটি একটি ক্যোয়ারিতে রাখার একটি উপায়। আমার অ্যাডেন্ডাম 2 মিনিট আগে দেখুন।
হারিকান

1
@ দ্য সুরিকান, এই সমাধানটি দুর্দান্ত দেখায় তবে অত্যন্ত ত্রুটিযুক্ত । খুব বড় একটি সন্নিবেশ করানোর চেষ্টা করুন Idএবং আপনার সমস্ত এলোমেলো প্রশ্নগুলি আপনাকে সেটিকে ফিরিয়ে দেবে Id
পেসারিয়ার

1
FLOOR(RAND()*MAX(id))বৃহত্তর আইডিস ফেরতের দিকে পক্ষপাতদুষ্ট।
রিক জেমস

3

বরং একটি বৃহত টেবিল থেকে প্রচুর এলোমেলো সারি ফিরতে আমার একটি প্রশ্নের প্রয়োজন ছিল 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);

3

@ রিডসিওর উত্তরটি আমি উন্নত করেছি। এটি সবচেয়ে কার্যকর ক্যোয়ারী যা আমি ফাঁকাগুলির সাথে একটি বৃহত, সমানভাবে বিতরণ করা টেবিলটিতে খুঁজে পেতে পারি (>> ২.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)

যা চলছে তা আমাকে আনপ্যাক করুন।

  1. @max := (SELECT MAX(id) FROM table)
    • আমি গণনা করছি এবং সর্বোচ্চ সঞ্চয় করছি। খুব বড় টেবিলের জন্য, MAX(id)প্রতিবার যখন আপনার একটি সারির প্রয়োজন হয় তখন গণনার জন্য সামান্য ওভারহেড থাকে
  2. SELECT FLOOR(rand() * @max) + 1 as rand)
    • একটি এলোমেলো আইডি পায়
  3. 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

আমার 30 টি এলোমেলো রেকর্ড দরকার, তাই আমার জিজ্ঞাসার LIMIT 1LIMIT 30
যেকোন

@ হাসান আপনার উচিত হবে না, পরিবর্তনটি LIMIT 1আপনাকে LIMIT 30টেবিলের এলোমেলো পয়েন্ট থেকে পরপর 30 টি রেকর্ড পেতে পারে । পরিবর্তে (SELECT id FROM ....মাঝখানে অংশটির 30 টি কপি থাকা উচিত ।
হ্যান্স জেড

আমি চেষ্টা করেছি তবে Riedsioউত্তরটি আরও দক্ষ বলে মনে হচ্ছে না । আমি পিএইচপি .0.০.২২ এবং মারিয়্যাডবি ব্যবহার করে পৃষ্ঠায় সেকেন্ডে ৫০০ সেকেন্ড হিটের সাথে সেন্টোস tried এ চেষ্টা করেছি, Riedsioউত্তরের সাথে আমি পেয়েছি ৫০০ ++ এর বেশি সফল সাড়া, তারপরে আপনার উত্তরটি পেয়েছি।
হাসান 14

1
@ হাসান রিডিসিওর উত্তরটি 1 টি সারি দেয়, এটি আপনাকে n সারি দেয়, পাশাপাশি জিজ্ঞাসাবাদ করার জন্য I / O ওভারহেডে কেটে দেয়। আপনি সারিগুলি দ্রুত পেতে সক্ষম হবেন তবে আপনার সিস্টেমে আরও বেশি লোড সহ।
হ্যান্স জেড

3

আমি এই 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 জন্য, মূল প্রশ্নের সাথে বিপরীতে।
ফ্যাবিয়ান শেমংলার

2

এখানে একটি গেম চেঞ্জার যা অনেকের পক্ষে সহায়ক হতে পারে;

আমার কাছে 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 এমএস লাগলো (পিএইচপি পাশের সমস্ত ক্রিয়াকলাপ সহ)


3
আপনাকে LIMITকিছুটা বাড়ানোর পরামর্শ দিন - আপনি সদৃশগুলি পেতে পারেন।
রিক জেমস

2

সমস্ত সেরা উত্তর ইতিমধ্যে পোস্ট করা হয়েছে (মূলত যারা লিঙ্কটি উল্লেখ করেছেন http://jan.kneschke.de/projects/mysql/order-by-rand/ )।

আমি আরেকটি গতি বাড়ানোর সম্ভাবনাটি চিহ্নিত করতে চাই - ক্যাশে করা । আপনার এলোমেলো সারি কেন দরকার তা ভেবে দেখুন। সম্ভবত আপনি কোনও ওয়েবসাইটে কিছু এলোমেলো পোস্ট বা এলোমেলো বিজ্ঞাপন প্রদর্শন করতে চান। আপনি যদি 100 রেক / সেকেন্ড পাচ্ছেন, তবে কি প্রতিটি দর্শকের এলোমেলো সারি পাওয়া দরকার? সাধারণত এই এক্স এলোমেলো সারিগুলিকে 1 সেকেন্ডের জন্য (বা এমনকি 10 সেকেন্ড) ক্যাশে করা পুরোপুরি ঠিক। একই 1 সেকেন্ডের 100 জন অনন্য দর্শক একই র্যান্ডম পোস্টগুলি পান কিনা তা বিবেচ্য নয়, কারণ পরের দ্বিতীয় দ্বিতীয় 100 জন দর্শক বিভিন্ন সেট পোস্ট পাবেন।

এই ক্যাচিংটি ব্যবহার করার সময় আপনি এলোমেলো তথ্য পাওয়ার জন্য কিছু ধীর সমাধানও ব্যবহার করতে পারেন কারণ এটি আপনার রেকর্ড / সেকেন্ড নির্বিশেষে প্রতি সেকেন্ডে একবারে মাইএসকিউএল থেকে নেওয়া হবে।


2

এটি সুপার দ্রুত এবং আপনার শূন্যস্থান থাকলেও এটি 100% এলোমেলো।

  1. xআপনার উপলব্ধ সারিগুলির সংখ্যা গণনা করুনSELECT COUNT(*) as rows FROM TABLE
  2. a_1,a_2,...,a_100 এবং এর মধ্যে 10 স্বতন্ত্র এলোমেলো সংখ্যা চয়ন করুনx
  3. আপনার সারিগুলি এর মতো প্রশ্ন করুন: SELECT * FROM TABLE LIMIT 1 offset a_ii = 1, ..., 10 এর জন্য

আমি বই এই হ্যাক পাওয়া এসকিউএল Antipatterns থেকে বিল Karwin


আমি একই সমাধান সম্পর্কে ভাবছিলাম, দয়া করে আমাকে বলুন, এটি কি অন্য পদ্ধতিগুলির পরে দ্রুত হয়?
জি। আদনানে

@ জি.আডনে তার দ্রুত বা ধীর না হয়ে স্বীকৃত উত্তর, তবে স্বীকৃত উত্তর আইডির সমান বন্টন ধরে নিয়েছে। এটির নিশ্চয়তা দেওয়া যায় এমন কোনও দৃশ্য আমি কল্পনা করতে পারি না। এই SELECT column FROM table ORDER BY RAND() LIMIT 10দ্রবণটি ও (1) এ থাকে যেখানে সমাধানটি ও (এনলগ (এন)) এ থাকে। হ্যাঁ, এটি দ্রুত সমাধান এবং এটি কোনও আইডির বিতরণের জন্য কাজ করে।
অ্যাডাম

না, কারণ গৃহীত সমাধানের জন্য পোস্ট করা লিঙ্কে, অন্যান্য পদ্ধতি রয়েছে, আমি জানতে চাই যে এই সমাধানটি দ্রুত কিনা অন্যরা, অন্যান্য উপায়ে, আমরা অন্যটিকে খুঁজে পাওয়ার চেষ্টা করতে পারি, এজন্য আইএম জিজ্ঞাসা করতে পারি, যেভাবেই হোক, +1 তোমার উত্তরের জন্য. আমি একই জিনিসটি ব্যবহার করছিলাম
জি। অ্যাডনে

এমন একটি কেস রয়েছে যখন আপনি x সংখ্যক সারি পেতে চান তবে অফসেটটি টেবিলের শেষ প্রান্তে চলে যায় যা <x সারি বা শুধুমাত্র 1 টি সারি ফিরে আসবে। আমি আপনার উত্তর দেখতে পাইনি আগে আমি খনি পোস্ট কিন্তু আমি এটা এখানে পরিষ্কার করেছেন stackoverflow.com/a/59981772/10387008
ZOLDIK

@ জোলডিক দেখে মনে হচ্ছে আপনি অফসেটের পরে প্রথম 10 টি সারি বেছে নিয়েছেন x। আমি যুক্তি দিয়ে বলব যে এটি 10 ​​টি সারির এলোমেলো প্রজন্ম নয়। আমার উত্তরে, আপনাকে তিনবার 10 বার ধাপে ক্যোরিটি চালাতে হবে, অর্থাত্ মৃত্যুদণ্ডপ্রাপ্তির জন্য কেবল একটি সারি পাওয়া যায় এবং যদি টেবিলের শেষে অফসেটটি থাকে তবে চিন্তার দরকার নেই।
অ্যাডাম

1

আপনার যদি কেবল একটি পঠন-অনুরোধ থাকে

একটি অস্থায়ী টেবিলের সাহায্যে @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;

আপনার যদি অনেকগুলি পড়ার অনুরোধ থাকে

  1. সংস্করণ: আপনি টেবিলটি tmp_randorderঅবিচলিত রাখতে পারতেন , এটিকে ডেটেটেবল_আইডলিস্ট বলে। নির্দিষ্ট ব্যবধানে (দিন, ঘন্টা) সেই টেবিলটি পুনরায় তৈরি করুন, যেহেতু এটিও গর্ত পাবে। যদি আপনার টেবিলটি সত্যিই বড় হয়ে যায় তবে আপনি গর্তগুলি আবারও পূরণ করতে পারেন

    dt.id = l.data_id যেখানে ডেট.আইডি নাল, সেখানে ডেটাটেবল ডিটি যোগ করুন ডেটাটেবল_আইডিলিস্ট থেকে সম্পূর্ণ l.data_id নির্বাচন করুন;

  2. সংস্করণ: আপনার ডেটাসেটটি সরাসরি ডেটেবলে বা অবিচ্ছিন্ন অতিরিক্ত টেবিলটিতে একটি এলোমেলো_সোর্টার কলাম দিন datatable_sortorder। সেই কলামটি সূচক করে। আপনার অ্যাপ্লিকেশনটিতে একটি র্যান্ডম-মান তৈরি করুন (আমি এটি কল করব $rand)।

    select l.*
    from datatable l 
    order by abs(random_sortorder - $rand) desc 
    limit 1;

এই সমাধানটি 'প্রান্ত সারিগুলিকে' সর্বোচ্চ এবং সর্বনিম্ন এলোমেলো_সোর্টর্ডারের সাথে বৈষম্যযুক্ত করে তাই তাদের বিরতিগুলিতে পুনরায় সাজান (দিনে একবার)।


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;

1

একটি অটোজেনারেটেড আইডি থাকলে আমি বেশ ভাল দেখতে পাই যে মডুলো অপারেটর '%' ব্যবহার করা। উদাহরণস্বরূপ, যদি আপনার ,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;

এটির জন্য একটি পূর্ণ স্ক্যানের প্রয়োজন, তবে এটি র‌্যান্ডের অর্ডার থেকে দ্রুত এবং আমার মতে এই থ্রেডে উল্লিখিত অন্যান্য বিকল্পগুলির চেয়ে বোঝা সহজ। এছাড়াও ডিবিতে লেখা সিস্টেমটি যদি ব্যাচগুলিতে সারিগুলির সেট তৈরি করে তবে আপনি যেখানে আশা করছেন তেমন এলোমেলো ফলাফল নাও পেতে পারেন।


2
এখন যেহেতু আমি এটিই মনে করি, প্রতিবার যখন আপনি কল করুন এলোমেলো সারিগুলির যদি আপনার প্রয়োজন হয় তবে এটি অকেজো। আমি কেবল কিছু গবেষণা করার জন্য একটি সেট থেকে এলোমেলো সারি পাওয়ার প্রয়োজন সম্পর্কে ভাবছিলাম। আমি এখনও মনে করি অন্য ক্ষেত্রে সহায়তা করার জন্য মডুলো একটি ভাল জিনিস। র‌্যান্ড অপারেশনের মাধ্যমে অর্ডারটি কমিয়ে আনার জন্য আপনি প্রথম পাস ফিল্টার হিসাবে মডুলো ব্যবহার করতে পারেন।
নিকোলাস কোহেন

1

আপনি যদি একটি এলোমেলো রেকর্ড চান (আইডির মধ্যে ফাঁক রয়েছে কিনা তা):

PREPARE stmt FROM 'SELECT * FROM `table_name` LIMIT 1 OFFSET ?';
SET @count = (SELECT
        FLOOR(RAND() * COUNT(*))
    FROM `table_name`);

EXECUTE stmt USING @count;

সূত্র: https://www.warpconduit.net/2011/03/23/selecting-a-random-record-using-mysql-benchmark-results/#comment-1266


1

আমি সমস্ত উত্তর দেখেছি এবং আমি মনে করি না যে কেউ এই সম্ভাবনার কথা মোটেও উল্লেখ করেছেন এবং কেন তা নিশ্চিত নন।

আপনি যদি সামান্য ব্যয় করে অত্যন্ত সরলতা এবং গতি চান, তবে আমার কাছে মনে হয় ডিবিতে প্রতিটি সারির বিপরীতে একটি এলোমেলো সংখ্যার সংরক্ষণ করা বুদ্ধিমান। কেবল একটি অতিরিক্ত কলাম তৈরি করুন random_number, এবং এটির ডিফল্ট সেট করুন RAND()। এই কলামে একটি সূচক তৈরি করুন।

তারপরে আপনি যখন একটি সারিটি পুনরুদ্ধার করতে চান তখন আপনার কোডে একটি এলোমেলো সংখ্যা তৈরি করুন (পিএইচপি, পার্ল, যাই হোক না কেন) এবং এটি কলামের সাথে তুলনা করুন।

SELECT FROM tbl WHERE random_number >= :random LIMIT 1

আমার ধারণা, যদিও এটি একটি একক সারির জন্য খুব ঝরঝরে, ওপির মতো দশ সারি জিজ্ঞাসা করেছিল আপনাকে এটি আলাদা আলাদা দশবার কল করতে হবে (বা আমাকে সঙ্গে সঙ্গে পালিয়ে যাওয়ার মতো একটি চতুর ঝাঁকুনি দিয়ে আসবে)


এটি আসলে খুব সুন্দর এবং দক্ষ পদ্ধতি is একমাত্র ফিরে আসার বিষয়টি হ'ল আপনি গতির জন্য স্থান কেনাবেচা করেছেন যা আমার মতে একটি ন্যায্য চুক্তির মতো বলে মনে হচ্ছে।
তোচুকু নেকমডিলিম

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

0

নিম্নলিখিতটি আইডি কলামের চেয়ে দ্রুত, নিরপেক্ষ এবং স্বতন্ত্র হওয়া উচিত। তবে এটি গ্যারান্টি দেয় না যে প্রত্যাবর্তিত সারিগুলির সংখ্যার সাথে প্রত্যাবর্তন করা সারিগুলির সংখ্যা মেলে।

SELECT *
FROM t
WHERE RAND() < (SELECT 10 / COUNT(*) FROM t)

ব্যাখ্যা: ধরে নিচ্ছি আপনি ১০০ টির মধ্যে ১০ টি সারি চান তবে প্রতিটি সারিতে SELECTed হওয়ার সম্ভাবনা রয়েছে যা দ্বারা অর্জন করা যেতে পারে WHERE RAND() < 0.1। এই পদ্ধতির 10 টি সারি গ্যারান্টি দেয় না; তবে যদি ক্যোয়ারী যথেষ্ট সময় চালানো হয় তবে নির্বাহের জন্য প্রতি সারির গড় সংখ্যা 10 এর কাছাকাছি হবে এবং টেবিলের প্রতিটি সারি সমানভাবে নির্বাচন করা হবে।


0

আপনি সহজেই কোনও সীমাবদ্ধতার সাথে একটি এলোমেলো অফসেট ব্যবহার করতে পারেন

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;

-1

আমি এই প্রশ্নটি ব্যবহার:

select floor(RAND() * (SELECT MAX(key) FROM table)) from table limit 10

প্রশ্নের সময়: 0.016 এস


1,2,9,15 এর মতো পিকে রয়েছে। উপরের ক্যোয়ারী অনুসারে আপনি 4, 7, 14, 11 এর মতো সারি পাবেন যা অপ্রতুল!
জুনেদ আতারি

-2

আমি এটি এইভাবে করি:

select * 
from table_with_600k_rows
where rand() < 10/600000
limit 10

আমি এটি পছন্দ করি কারণ অন্য টেবিলের প্রয়োজন হয় না, এটি লেখা সহজ, এবং এটি সম্পাদন করা খুব দ্রুত।


5
এটি পূর্ণ টেবিল স্ক্যান এবং এটি কোনও সূচি ব্যবহার করে না। বড় টেবিল এবং ব্যস্ত পরিবেশের জন্য এটি কোনও বড় নয়।
ম্যাট

-2

একটি টেবিল থেকে এলোমেলো তথ্য পেতে নীচের সহজ ক্যোয়ারী ব্যবহার করুন।

SELECT user_firstname ,
COUNT(DISTINCT usr_fk_id) cnt
FROM userdetails 
GROUP BY usr_fk_id 
ORDER BY cnt ASC  
LIMIT 10

আপনি যদি কোনও যোগদানের বিবৃতি ব্যবহার করতে চান এবং যেখানে ফিল্টার ব্যবহার করতে পারেন।
মনোজ

3
কোয়েরির কোন অংশ থেকে আপনি এলোমেলো-নেস পেয়েছেন?
মার্কি 555

-4

আমার ধারণা এটি সর্বোত্তম সম্ভাব্য উপায় ..

SELECT id, id * RAND( ) AS random_no, first_name, last_name
FROM user
ORDER BY random_no

8
হেইল না, টেবিল থেকে এলোমেলো সারি পাওয়ার সবচেয়ে খারাপ উপায়। এটি পূর্ণ টেবিল স্ক্যান + ফাইলসোর্ট + টিএমপি টেবিল = খারাপ পারফরম্যান্স।
ম্যাট

1
পারফরম্যান্সের পাশাপাশি এটি একেবারে এলোমেলো থেকেও অনেক দূরে; আপনি আইডি এবং একটি এলোমেলো সংখ্যার প্রোডাক্ট দ্বারা অর্ডার করছেন, কেবল কোনও এলোমেলো সংখ্যা দ্বারা অর্ডার না দিয়ে, যার অর্থ নিম্ন আইডের সাথে সারিগুলি আপনার ফলাফলের সেটটিতে আগে উপস্থিত হওয়ার পক্ষপাতদুষ্ট হতে চলেছে।
মার্ক এ Amery
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.