Как мне подойти к логике базы данных за функцией «забыть об этом»? - PullRequest
3 голосов
/ 23 июня 2011

Итак, допустим, у меня есть таблица users и таблица pages. Допустим, я хочу позволить пользователям скрывать / забывать / игнорировать определенные страницы. На данный момент, я могу думать о двух возможных подходах:

Внешнее соединение с null соответствием:

Я могу создать отдельную таблицу ignored_pages со столбцами user_id и page_id, записывая в нее INSERT INTO ignored_pages (user_id, page_id) VALUES (1,2);, когда пользователь с идентификатором 1 игнорирует страницу с идентификатором 2.

Тогда я могу запустить что-то вроде SELECT pages.* FROM pages LEFT OUTER JOIN ignored_pages ON pages.id = ignored_pages.page_id WHERE ignored_pages.user_id = 1 AND ignored_pages.id IS NULL;

РЕДАКТИРОВАТЬ: Джо Стефанелли указал на ошибку в моем запросе. Должно быть SELECT pages.* FROM pages LEFT OUTER JOIN ignored_pages ON pages.id = ignored_pages.page_id AND ignored_pages.user_id = 1 WHERE ignored_pages.id IS NULL;

Подзапрос и NOT IN:

Я могу использовать ту же таблицу «многие ко многим», а затем запустить что-то вроде SELECT pages.* FROM pages WHERE page_id NOT IN (SELECT page_id FROM ignored_pages WHERE user_id = 1);.


Есть ли лучшая практика или ряд практических правил или (вероятно) лучший подход к этой проблеме, чем тот, который я использую?

Ответы [ 4 ]

1 голос
/ 23 июня 2011
1 голос
/ 23 июня 2011

Для лучшей производительности вы должны использовать NOT EXISTS

SELECT pages.* 
FROM pages
WHERE NOT EXISTS(
   SELECT NULL
   FROM ignored_pages
   WHERE user_id = 1 AND ignored_pages.page_id = pages.page_id)
1 голос
/ 23 июня 2011

Ваша лучшая производительность на самом деле может быть NOT EXISTS

SELECT p.* 
    FROM pages p
    WHERE NOT EXISTS(SELECT 1 
                         FROM ignored_pages 
                         WHERE user_id = 1 
                             AND page_id = p.id);

Если вы решите придерживаться опции LEFT JOIN, вам нужно исправить этот запрос, чтобы проверить user_id в условии соединения, а не в предложении WHERE.

SELECT pages.* 
    FROM pages 
        LEFT OUTER JOIN ignored_pages 
            ON pages.id = ignored_pages.page_id 
                AND ignored_pages.user_id = 1 
    WHERE ignored_pages.id IS NULL;
0 голосов
/ 23 июня 2011

На этой странице есть хорошее сравнение использования LEFT OUTER JOIN с NOT EXISTS.Ссылка , связанная с на этой странице, показывает, что NOT EXISTS либо сопоставим, либо быстрее, чем NOT IN, по крайней мере для примера в этом блоге.Первая ссылка показывает, что NOT EXISTS работает почти в два раза лучше (циклы процессора и время выполнения), чем LEFT OUTER JOIN, при условии, что у вас есть индекс для всех соединяемых / сопоставляемых столбцов.Индекс для ignored_pages, скорее всего, будет выглядеть примерно так:

CREATE UNIQUE CLUSTERED INDEX IX_Ignored_Pages ON ignored_pages (user_id, page_id);

При адаптации к вашему коду синтаксис NOT EXISTS будет выглядеть примерно так:

SELECT p.*
FROM pages p
WHERE NOT EXISTS (
   SELECT 1
   FROM ignored_pages i
   WHERE i.user_id = @user_id
   AND i.page_id = p.page_id
);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...