اختيار سريع من صف عشوائي من جدول كبير في الخلية

StackOverflow https://stackoverflow.com/questions/211329

  •  03-07-2019
  •  | 
  •  

سؤال

ما هي طريقة سريعة لتحديد صف عشوائي من الخلية الطاولة ؟

أنا أعمل في php, ولكن أنا مهتم في أي حل حتى لو كان بلغة أخرى.

هل كانت مفيدة؟

المحلول

والاستيلاء على جميع والهوية، واختيار واحد عشوائي منه، واسترداد كامل على التوالي.

إذا كنت تعرف على هوية متسلسلة بدون ثقوب، يمكنك فقط انتزاع أقصى الحدود وحساب معرف عشوائي.

إذا هناك ثغرات هنا وهناك ولكن في الغالب القيم متسلسلة، وكنت لا يهتمون العشوائية الانحراف قليلا، والاستيلاء على قيمة الحد الأقصى، وحساب على الهوية، وتحديد الصف الأول مع معرف يساوي أو أعلى واحد كنت المحسوبة. سبب انحراف هو أن معرف التالية مثل هذه الثقوب سيكون له فرصة أكبر للاختياره من تلك التي تتبع هوية أخرى.

إذا كنت من أجل عشوائي من قبل، وأنت تسير أن يكون رهيب الجدول المسح على يديك، وكلمة سريعة لا ينطبق على مثل هذا الحل.

لا تفعل ذلك، ولا يجب عليك أن تأمر من قبل GUID، فمن لديه نفس المشكلة.

نصائح أخرى

وعرفت هناك كان لابد من طريقة للقيام بذلك في استعلام واحد بطريقة سريعة. وهنا هو:

وهناك طريقة سريعة دون تدخل خارجي من التعليمات البرمجية، مجد

http://jan.kneschke.de/projects/mysql/order -by-راند /

SELECT name
  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;

وميدياويكي يستخدم حيلة مثيرة للاهتمام (على الخاص ويكيبيديا: ميزة عشوائية): الجدول مع المواد لديه عمود إضافي مع عدد عشوائي (ولدت عندما يتم إنشاء المقالة). للحصول على المادة عشوائية، وتوليد رقم عشوائي والحصول على هذه المادة مع قيمة أكبر المقبل أو أصغر (لا أذكر أي) في العمود رقم عشوائي. مع فهرس، وهذا يمكن أن تكون سريعة جدا. (وميدياويكي هو مكتوب في PHP وضعت لماي).

وهذا النهج يمكن أن يسبب مشكلة إذا يتم توزيع الأرقام الناتجة سيئة. IIRC، تم إصلاح هذا على ميدياويكي، حتى إذا كنت قررت أن تفعل ذلك بهذه الطريقة يجب أن نلقي نظرة على قانون لنرى كيف يتم ذلك حاليا (ربما بشكل دوري تجديد العمود رقم عشوائي).

وهنا الحل الذي يعمل بسرعة إلى حد ما، وأنها تحصل على تحسين توزيع عشوائي من دون الاعتماد على القيم معرف يجري متجاورة أو تبدأ في 1.

SET @r := (SELECT ROUND(RAND() * (SELECT COUNT(*) FROM mytable)));
SET @sql := CONCAT('SELECT * FROM mytable LIMIT ', @r, ', 1');
PREPARE stmt1 FROM @sql;
EXECUTE stmt1;

وربما يمكن أن تفعل شيئا مثل:

SELECT * FROM table 
  WHERE id=
    (FLOOR(RAND() * 
           (SELECT COUNT(*) FROM table)
          )
    );

وهذا على افتراض أرقام التعريف الخاصة بك كلها متتابعة مع أي ثغرات.

إضافة عمود يحتوي على احتساب قيمة عشوائية إلى كل صف ، واستخدام ذلك في ترتيب شرط الحد إلى نتيجة واحدة عند الاختيار.هذا يعمل بشكل أسرع من وجود طاولة الفحص الذي ORDER BY RANDOM() الأسباب.

تحديث: كنت لا تزال بحاجة إلى حساب بعض قيمة عشوائية قبل إصدار SELECT البيان عند استرجاعها ، بطبيعة الحال ، على سبيل المثال

SELECT * FROM `foo` WHERE `foo_rand` >= {some random value} LIMIT 1

وطريقة سهلة ولكنها بطيئة سيكون (جيد للجداول الشريك الأصغر)

SELECT * from TABLE order by RAND() LIMIT 1

في رمز زائف:

sql "select id from table"
store result in list
n = random(size of list)
sql "select * from table where id=" + list[n]

وهذا يفترض أن id هو مفتاح فريد (الأساسي).

هناك طريقة أخرى لإنتاج عشوائية الصفوف فقط باستخدام استعلام بدون ترتيب حسب راند().فإنه ينطوي على المستخدم تعريف المتغيرات.انظر كيفية إنتاج عشوائية الصفوف من الجدول

ومن أجل العثور صفوف عشوائية من جدول، لا تستخدم ORDER BY RAND () لأنه يجبر الخلية للقيام نوع ملف كامل وبعد ذلك فقط لاسترداد عدد الحد الصفوف المطلوبة. من أجل تجنب هذا النوع ملف كامل، استخدم الدالة RAND () فقط في بند فيها. وسوف تتوقف بمجرد أن تصل إلى العدد المطلوب من الصفوف. نرى http://www.rndblog.com/how-to- اختر-الصفوف العشوائية-في ماي /

وإذا لم تقم بحذف الصف في هذا الجدول، والطريقة الأكثر فعالية هي:

و(إذا كنت تعرف هوية mininum تخطاها)

SELECT MIN(id) AS minId, MAX(id) AS maxId FROM table WHERE 1

$randId=mt_rand((int)$row['minId'], (int)$row['maxId']);

SELECT id,name,... FROM table WHERE id=$randId LIMIT 1

لاختيار عدة صفوف عشوائية من جدول معين (يقول 'كلمات')، وجاء فريقنا مع هذا الجمال:

SELECT * FROM
`words` AS r1 JOIN 
(SELECT  MAX(`WordID`) as wid_c FROM `words`) as tmp1
WHERE r1.WordID >= (SELECT (RAND() * tmp1.wid_c) AS id) LIMIT n

والكلاسيكية "معرف اختر من الجدول ORDER BY RAND () LIMIT 1" هو في الواقع موافق.

وانظر المقتطف التالي من دليل الخلية:

إذا كنت تستخدم LIMIT ROW_COUNT مع ORDER BY، ينتهي الخلية الفرز بمجرد أن وجدت الصفوف ROW_COUNT الأولى من نتيجة فرزها، بدلا من فرز نتيجة بأكملها.

ومع نظام يو سوف تفعل الجدول مسح كامل. أفضل حالاتها إذا كنت تفعل حدد عدد (*)، وبعد الحصول على التوالي عشوائي = ROWNUM بين 0 و التسجيل الماضي

ونلقي نظرة على هذا الرابط من يناير Kneschke أو هذه الإجابة SO كما كلاهما مناقشة نفس السؤال. الجواب SO يذهب أكثر خيارات مختلفة أيضا ولها بعض اقتراحات جيدة اعتمادا على احتياجاتك. يناير يذهب على كل الخيارات المختلفة وخصائص الأداء لكل منها. وقال انه ينتهي مع التالية لالأسلوب الأكثر الأمثل التي يمكن من خلالها القيام بذلك ضمن الخلية حدد:

SELECT name
  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;

وHTH،

و-Dipin

وأنا قليلا جديدة على SQL ولكن ماذا عن توليد رقم عشوائي في PHP وباستخدام

SELECT * FROM the_table WHERE primary_key >= $randNr

وهذا لا يحل المشكلة مع ثقوب في الجدول.

ولكن هنا تطور على اقتراح lassevks:

SELECT primary_key FROM the_table

استخدم mysql_num_rows () في PHP تخلق رقم عشوائي استنادا إلى النتيجة أعلاه:

SELECT * FROM the_table WHERE primary_key = rand_number

وعلى الجانب علما مدى بطيئة غير SELECT * FROM the_table:
إنشاء رقم عشوائي على أساس mysql_num_rows() ثم تحريك المؤشر البيانات إلى أن mysql_data_seek() نقطة. كيف بطيئة سوف يكون هذا على جداول كبيرة مع أقول مليون صف؟

وأنا واجهت مشكلة حيث لم تكن متتابعة بلدي معرفات. ما جئت حتى مع هذا.

SELECT * FROM products WHERE RAND()<=(5/(SELECT COUNT(*) FROM products)) LIMIT 1

والصفوف عاد ما يقرب من 5، ولكنني قصرها على 1.

إذا كنت ترغب في إضافة أخرى حيث يصبح بند قليلا أكثر إثارة للاهتمام. تقول انك تريد للبحث عن المنتجات على الخصم.

SELECT * FROM products WHERE RAND()<=(100/(SELECT COUNT(*) FROM pt_products)) AND discount<.2 LIMIT 1

ما عليك القيام به هو التأكد من كنت ستعود كافية نتيجة وهذا هو السبب ولدي الذي حددته ل100. وجود WHERE الخصم <كان 0.2 بند في فرعي 10X أبطأ، لذلك فمن الأفضل للعودة المزيد من النتائج والحد .

وأرى هنا الكثير من الحل. واحد أو اثنين يبدو طيب ولكن الحلول الأخرى لديها بعض القيود. ولكن الحل التالي ستعمل لجميع الأوضاع

select a.* from random_data a, (select max(id)*rand() randid  from random_data) b
     where a.id >= b.randid limit 1;

وهنا، الهوية، لا تحتاج إلى أن تكون متتابعة. يمكن أن يكون أي مفتاح / فريدة / لصناعة السيارات عمود زيادة الابتدائي. الرجاء راجع ما يلي أسرع طريقة لتحديد صف عشوائي من جدول الخلية الكبيرة

والشكر زيلور - www.techinfobest.com

استخدم الاستعلام أدناه للحصول على الصف عشوائي

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

في حالتي طاولتي غير معرف كما المفتاح الأساسي ، زيادة تلقائية مع أي ثغرات ، حتى أتمكن من استخدام COUNT(*) أو MAX(id) للحصول على عدد من الصفوف.

أنا جعلت هذا البرنامج النصي إلى اختبار أسرع العملية:

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 ms
  • ماكس: 0.241041183472 ms
  • النظام: 0.216960906982 ms

الجواب مع النظام الطريقة:

SELECT FLOOR(RAND() * (
    SELECT id FROM tbl ORDER BY id DESC LIMIT 1
)) n FROM tbl LIMIT 1

...
SELECT * FROM tbl WHERE id = $result;

لقد استخدمت هذه المهمة الإشارة من هنا

SELECT * FROM myTable WHERE RAND()<(SELECT ((30/COUNT(*))*10) FROM myTable) ORDER BY RAND() LIMIT 30;

وإنشاء وظيفة للقيام بذلك على الأرجح أفضل إجابة والأكثر أسرع الجواب هنا!

وبروز -. يعمل حتى مع الفجوات وسريع للغاية

<?

$sqlConnect = mysqli_connect('localhost','username','password','database');

function rando($data,$find,$max = '0'){
   global $sqlConnect; // Set as mysqli connection variable, fetches variable outside of function set as GLOBAL
   if($data == 's1'){
     $query = mysqli_query($sqlConnect, "SELECT * FROM `yourtable` ORDER BY `id` DESC LIMIT {$find},1");

     $fetched_data = mysqli_fetch_assoc($query);
      if(mysqli_num_rows($fetched_data>0){
       return $fetch_$data;
      }else{
       rando('','',$max); // Start Over the results returned nothing
      }
   }else{
     if($max != '0'){
        $irand = rand(0,$max); 
        rando('s1',$irand,$max); // Start rando with new random ID to fetch
     }else{

        $query = mysqli_query($sqlConnect, "SELECT `id` FROM `yourtable` ORDER BY `id` DESC LIMIT 0,1");
        $fetched_data = mysqli_fetch_assoc($query);
        $max = $fetched_data['id'];
        $irand = rand(1,$max);
        rando('s1',$irand,$max); // Runs rando against the random ID we have selected if data exist will return
     }
   }
 }

 $your_data = rando(); // Returns listing data for a random entry as a ASSOC ARRAY
?>

ويرجى أن نضع في اعتبارنا هذا الكود كما لم يتم اختباره بل هو مفهوم العمل للعودة إدخالات عشوائية حتى مع وجود ثغرات .. وطالما أن الفجوات ليست كبيرة بما يكفي للتسبب مسألة وقت التحميل.

تحليل طريقة سريعة وقذرة:

SET @COUNTER=SELECT COUNT(*) FROM your_table;

SELECT PrimaryKey
FROM your_table
LIMIT 1 OFFSET (RAND() * @COUNTER);

وتعقيد الاستعلام الأول هو O (1) للجداول MYISAM.

والاستعلام الثاني يرافق الجدول مسح كامل. تعقيد = O (ن)

تحليل طريقة القذرة وسريعة:

وحافظ على جدول منفصل لهذا الغرض فقط. يجب عليك أيضا إدراج نفس الصفوف في هذا الجدول كلما إدخال إلى الجدول الأصلي. الافتراض: لا الحذف

CREATE TABLE Aux(
  MyPK INT AUTO_INCREMENT,
  PrimaryKey INT
);

SET @MaxPK = (SELECT MAX(MyPK) FROM Aux);
SET @RandPK = CAST(RANDOM() * @MaxPK, INT)
SET @PrimaryKey = (SELECT PrimaryKey FROM Aux WHERE MyPK = @RandPK);

إذا يسمح الحذف،

SET @delta = CAST(@RandPK/10, INT);

SET @PrimaryKey = (SELECT PrimaryKey
                   FROM Aux
                   WHERE MyPK BETWEEN @RandPK - @delta AND @RandPK + @delta
                   LIMIT 1);

وتعقيد العام هو O (1).

وSELECT DISTINCT * FROM yourTable WHERE 4 = 4 LIMIT 1;

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top