2016-04-01 7 views
3

У меня есть таблица под названием «Статьи». Структура этой таблицы выглядит следующим образом: id (уникальный), категория (категория статьи, т. Е. Развлечения), название (название статьи), изображение (URL-адрес изображения статьи), ссылка (URL-адрес статья), счетчик (количество просмотров, которое имеет статья), dateStamp (дата публикации статьи).Получение случайных записей, основанных на категории

Предположим, я хочу распечатать 6 случайных развлекательных статей. Легкий, но менее эффективный способ обойти это делает что-то вроде

$result = $db->query("SELECT * FROM Articles WHERE category = 'entertainment' ORDER BY RAND() LIMIT 6); 

Вместо этого, как я могу сделать это более эффективно? Я знаю, что есть несколько сайтов, объясняющих альтернативы ORDER BY RAND(), но я просто не понимаю этих альтернатив. Я хочу понять, основываясь на моей структуре. Я пробовал несколько вещей, перетасовывая ассоциативный массив для создания случайного генератора, но все закончилось разочарованием, потому что я не мог заставить его работать правильно. Как я могу получить 6 случайных развлекательных статей, распечатанных без использования ORDER BY RAND()?

+0

Ваш большой стол (скажем, более 1000 записей)? Если нет, вы можете ВЫБРАТЬ все данные и использовать PHP, чтобы получить случайную строку внутри результата ... – Random

+0

@Random Это сейчас не большой, но в будущем это станет большим, поэтому я хочу, чтобы сейчас это решение, поэтому мне не нужно возвращаться и исправлять. – user2896120

ответ

1

Там нет универсального способа сделать это, один из эффективных вариантов для выбора случайного подмножества данных по заданным (по желанию) критерии, category в вашем случае. Обратите внимание на добавленный индекс в этот столбец.

SELECT 
    r1.* 
FROM 
    articles AS r1 
    INNER JOIN (SELECT(RAND() * (SELECT MAX(id) FROM articles)) AS id) AS r2 
WHERE 
    r1.id >= r2.id 
    AND r1.category = 'entertainment' 
LIMIT 6; 

Здесь данные с данными (например, 3.2M строки) и план выполнения:

mysql> SELECT COUNT(*) FROM articles; 
+----------+ 
| COUNT(*) | 
+----------+ 
| 3200000 | 
+----------+ 
1 row in set (0.00 sec) 

mysql> SELECT 
    r1.* 
FROM 
    articles AS r1 
    INNER JOIN (SELECT(RAND() * (SELECT MAX(id) FROM articles)) AS id) AS r2 
WHERE 
    r1.id >= r2.id 
    AND r1.category = 'entertainment' 
LIMIT 6; 
+---------+-------------+-----------------------------------------------------------+---------------+ 
| id  | topic  | message             | category  | 
+---------+-------------+-----------------------------------------------------------+---------------+ 
| 3153910 | JAX68VVH3FZ | Sed eu eros. Nam consequat dolor       | entertainment | 
| 3153911 | NIY23HWV0VM | tortor. Nunc commodo auctor velit. Aliquam nisl. Nulla eu | entertainment | 
| 3153912 | LKQ42FRB7LA | mus. Proin vel nisl. Quisque        | entertainment | 
| 3153913 | PFL39VHI9RM | gravida             | entertainment | 
| 3153914 | FGV59TUN9TQ | elit, pellentesque a, facilisis non, bibendum sed,  | entertainment | 
| 3153915 | OWH73EBZ1GW | ligula. Nullam enim. Sed nulla ante, iaculis    | entertainment | 
+---------+-------------+-----------------------------------------------------------+---------------+ 
6 rows in set (0.473 sec) 

mysql> explain extended 
SELECT 
    r1.* 
FROM 
    articles AS r1 
    INNER JOIN (SELECT(RAND() * (SELECT MAX(id) FROM articles)) AS id) AS r2 
WHERE 
    r1.id >= r2.id 
    AND r1.category = 'entertainment' 
LIMIT 6; 
+----+-------------+------------+--------+-----------------+---------+---------+-------+---------+----------+------------------------------+ 
| id | select_type | table  | type | possible_keys | key  | key_len | ref | rows | filtered | Extra      | 
+----+-------------+------------+--------+-----------------+---------+---------+-------+---------+----------+------------------------------+ 
| 1 | PRIMARY  | <derived2> | system | NULL   | NULL | NULL | NULL |  1 |  100 | NULL       | 
| 1 | PRIMARY  | r1   | ref | PRIMARY,cat_IDX | cat_IDX | 768  | const | 1560229 |  100 | Using index condition  | 
| 2 | DERIVED  | NULL  | NULL | NULL   | NULL | NULL | NULL | NULL | NULL  | No tables used    | 
| 3 | SUBQUERY | NULL  | NULL | NULL   | NULL | NULL | NULL | NULL | NULL  | Select tables optimized away | 
+----+-------------+------------+--------+-----------------+---------+---------+-------+---------+----------+------------------------------+ 
4 rows in set (0.00 sec) 

Разница в производительности saginificant (более чем в 10 раз), чем обычный случай за тот же объем данных:

mysql> SELECT * FROM articles WHERE category = 'entertainment' ORDER BY RAND() LIMIT 6; 
+---------+-------------+---------------------------------------------------------------------------+---------------+ 
| id  | topic  | message                 | category  | 
+---------+-------------+---------------------------------------------------------------------------+---------------+ 
| 2374491 | PZC33VGM0ML | Duis cursus, diam at pretium aliquet, metus urna convallis erat,   | entertainment | 
| 382306 | RFN88EPE4MI | malesuada fames ac turpis egestas. Aliquam fringilla cursus purus. Nullam | entertainment | 
| 1867986 | KWX30ULB1FR | pede.                  | entertainment | 
| 1528863 | ADX52RRJ3MQ | lacus. Mauris non               | entertainment | 
| 2188208 | AOD82PXQ6FS | diam luctus lobortis. Class aptent taciti sociosqu ad litora    | entertainment | 
| 878426 | ABV08HTB2PG | eu eros. Nam consequat dolor vitae dolor. Donec fringilla. Donec   | entertainment | 
+---------+-------------+---------------------------------------------------------------------------+---------------+ 
6 rows in set (5.726 sec) 

Надеюсь, это вам поможет.

+0

Спасибо за ваш ответ! У меня есть один вопрос: что такое r1, когда вы говорите SELECT r1. *? – user2896120

+0

Кроме того, у меня есть 7 развлекательных записей. Я хочу, чтобы 6 случайных развлекательных статей отображались точно, этот запрос иногда отображает 4, 5 и т. Д. Номер 1-6. Что бы я сделал, если бы я хотел, чтобы 6 статей отображались точно? – user2896120

Смежные вопросы