2017-01-11 4 views
1

Я две таблицы tbl_data и tbl_user_dataSql эффективный запрос из нескольких таблиц

Структура из tbl_data

id (int) (primary) 
names (varchar) 
dept_id (int) 

Структура из tbl_user_data:

id (int) (primary) 
user_id (int) 
names_id (int) 

tbl_data.id и tbl_user_data.names_id являются внешними ключом

Я ситуация, где я, чтобы выбрать 25 случайных записей из tbl_data, который не служили раньше конкретному пользователю. Поэтому я создал tbl_user_data, который будет хранить user_id и names_id (от tbl_data, который уже подан). Я немного смущен, как запросить от имени этого или есть ли другой способ сделать это эффективно?

Примечание:tbl_data имеет более 5 миллионов записей.

До сих пор я написал это, но кажется, что это неправильно.

SELECT td.names, td.dept_id 
FROM tbl_data AS td 
LEFT JOIN tbl_user_data AS tud ON td.id = tud.names_id 
WHERE tud.user_id !=2 
ORDER BY RAND() LIMIT 25 
+0

плюс тег mysql – dstudeba

ответ

1

Две вещи:

... Во-первых вам нужно LEFT JOIN .... IS NULL шаблон, чтобы выбрать ваш пока еще не служивших пунктов. Вам нужно указать идентификатор пользователя в предложении ON, чтобы он работал правильно.

SELECT td.names, td.dept_id 
    FROM tbl_data AS td 
    LEFT JOIN tbl_user_data AS tud ON td.id = tud.names_id 
            AND tud.user_id = 2 
WHERE tud.id IS NULL 
ORDER BY RAND() LIMIT 25 

Во-вторых, ORDER BY RAND() LIMIT ... является заведомо низкой эффективностью на большом столе. Он должен выбрать всю таблицу, а затем отсортировать ее, а затем отбросить все, кроме 25 предметов. Это массово расточительно и никогда не будет действовать прилично.

Вы можете сделать это немного менее расточительным, отсортировав только значения id, а затем используя их, чтобы получить другую информацию.

Это получает ваши 25 случайных значений идентификатора.

    SELECT td.id 
        FROM tbl_data AS td 
        LEFT JOIN tbl_user_data AS tud ON td.id = tud.names_id 
                AND tud.user_id = 2 
        WHERE tud.id IS NULL 
        ORDER BY RAND() 
        LIMIT 25 

Это получает ваши имена и значения dept_id.

SELECT a.names, a.dept_id 
    FROM tbl_data AS a 
    JOIN (
       SELECT td.id 
        FROM tbl_data AS td 
        LEFT JOIN tbl_user_data AS tud ON td.id = tud.names_id 
                AND tud.user_id = 2 
        WHERE tud.id IS NULL 
        ORDER BY RAND() 
        LIMIT 25 
     ) b ON a.id = b.id 

Но, это все еще расточительно.Вы можете захотеть создать рандомизированную версию этой таблицы tbl_data, а затем использовать ее последовательно. Вы можете повторно рандомизировать его один раз в день, с чем-то вроде этого.

DROP TABLE tbl_data_random; 
INSERT INTO tbl_data_random FROM 
SELECT * 
    FROM tbl_data 
    ORDER BY RAND() 

Таким образом, вы не делаете сортировку снова и снова, просто чтобы отбросить результаты. Вместо этого вы производите время от времени.

+0

спасибо. Из фильма «Нолан» «Когда идея захватила мозг, ее почти невозможно искоренить». Я застрял в идее рандомизации и сохранения данных в другой таблице, но это действительно хорошая идея, чтобы показать случайные записи на дневной основе , – jpm

0

Создать индекс для names_id и user_id. Почему user_id varchar? Если вам нужно быть varchar и varchar очень длинный, создайте частичный индекс на user_id. Вы можете использовать EXPLAIN, чтобы узнать, какой индекс использует ваш запрос.

+0

мой плохой. user_id тоже int, я задал вопрос. – jpm

0

Как вы ничего не выбирая из tbl_user_data, вы можете использовать вместо этого существует:

SELECT td.names, td.dept_id 
FROM tbl_data AS td 
where exists (
    select 1 
    from tbl_user_data AS tud 
    where td.id = tud.names_id 
    and tud.user_id !=2 
) 
ORDER BY RAND() LIMIT 25 

Индекс на tbl_data (ID) и tbl_user_data (names_id, user_id) поможет.

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