Как избежать избыточных полей данных в наборе результатов при использовании JOIN? - PullRequest
5 голосов
/ 05 июля 2010

После объединения предполагается получение информации о пользователях вместе с их сообщениями для пользователей с определенным статусом:

SELECT * FROM user, message WHERE message.user_id=user.id AND user.status=1

Проблема состоит в том, что все строки об определенном пользователе в наборе результатов содержат избыточные столбцы, которые повторяютсяте же данные об этом пользователе (эти поля получены из пользовательской таблицы), только поля из таблицы сообщений содержат не избыточную информацию.Примерно так:

user.id  username email            message.id  subject
1        jane     jane@gmail.com   120         Notification 
1        jane     jane@gmail.com   122         Re:Hello 
1        jane     jane@gmail.com   125         Quotation
2        john     john@yahoo.com   127         Hi jane
2        john     john@yahoo.com   128         Fix thiss 
2        john     john@yahoo.com   129         Ok
3        jim      jim@msn.com      140         Re:Re:Quotation

Как видите, многие данные являются избыточными, и мы не хотим сначала находить пользователей, а затем обрабатывать их сообщения в виде петлевых структур или чего-то в этом роде.Следует избегать циклов, которые вызывают микро-запросы любой ценой.

Меня не беспокоит вывод моей программы, которая хорошо обрабатывается в пользовательском интерфейсе.Я думаю возможно, сетевой трафик, полученный при возврате результата этого запроса, может быть существенно уменьшен, если каким-либо образом мне удастся устранить повторение пользовательских данных во всех строках, относящихся к этому пользователю.

Ответы [ 4 ]

3 голосов
/ 05 июля 2010

Есть несколько вещей, которые вы должны знать.

Первое - это то, что конструкция SQL JOIN по умолчанию, по сути, является перекрестным произведением, ограниченным предложением WHERE.Это означает, что он мультипликативный - вы получаете дублированные результаты, которые затем сокращаете.Вы также должны быть осторожны при наличии полей NULL.

Во-вторых, существует ключевое слово DISTINCT.Когда вы префиксом столбца в выделении, вы получите не более одного экземпляра определенного значения для этого столбца в результатах.Таким образом, согласно вашему запросу, «SELECT DISTINCT user.id FROM» устранит избыточность на стороне сервера.

Третий способ состоит в том, что правильный способ решения этой проблемы, вероятно, не использует оператор *.,Я предлагаю:

SELECT user.id,username,email,subject FROM message m,user WHERE m.user_id=user.id AND user.status=1

Используется простой, понятный синтаксис неявного соединения, и он должен быть допустимым SQL на любом сервере.Я могу поручиться за это, работая с MySQL, по крайней мере.Кроме того, псевдоним таблицы 'message' обозначается как 'm'.

Как вы предполагаете, это уменьшит трафик с сервера SQL к вашей базе данных.

edit: если вы хотитеудалить «лишнюю» информацию электронной почты, вы не можете - вы должны сделать два разных запроса.Результаты SQL являются таблицами и должны быть прямоугольными, с заполнением всех известных значений.Нет такой же записи.

edit 2: Вам нужно только сделать два запроса.Например:

SELECT subject FROM message WHERE message.id IN (SELECT user.id FROM user WHERE status=1)

Это один запрос, который содержит вложенный запрос, поэтому он действительно совершает два обращения к базе данных.Но у него нет никаких программных циклов.

1 голос
/ 05 июля 2010

В стандарте SQL вы бы использовали NATURAL JOIN;это объединяет общие имена столбцов и сохраняет только одну копию этих общих имен.

На практике вы тщательно перечисляете нужные столбцы, а не прибегаете к сокращенной записи '*'.

1 голос
/ 05 июля 2010

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

0 голосов
/ 05 июля 2010

Предполагая, что вы можете использовать хранимую процедуру, вы можете написать ее для выполнения вышеуказанного запроса, а затем использовать курсор для хранения нулей для «избыточной информации», чтобы получить что-то вроде

user.id  username email            message.id  subject 
1        jane     jane@gmail.com   120         Notification  
null     null     null             122         Re:Hello  
null     null     null             125         Quotation 
2        john     john@yahoo.com   127         Hi jane 
null     null     null             128         Fix thiss  
null     null     null             129         Ok 
3        jim      jim@msn.com      140         Re:Re:Quotation

и затем вернуть этот набор результатов во временную таблицу. но в то время как это может уменьшить сетевой трафик, это добавит накладные расходы на обработку

Другой способ - запустить 2 запроса, один для получения информации о пользователе, а другой - для получения информации о сообщении, используя только связанный идентификатор пользователя, а затем выполнить «соединение» с использованием кода на стороне сервера приложений. что-то вроде

SELECT DISTINCT user.* FROM user, message WHERE message.user_id=user.id AND user.status=1

и

SELECT user.id, message.* FROM user, message WHERE message.user_id=user.id AND user.status=1

, что приведет к 2 поездкам в базу данных вместо 1, что в конечном итоге может быть медленнее, даже если сетевой трафик уменьшается.

И еще один способ - объединить эти 2 в один набор результатов с чем-то вроде

SELECT user.* FROM user, message WHERE message.user_id=user.id AND user.status=1
UNION ALL
SELECT user.id, message.* FROM user, message WHERE message.user_id=user.id AND user.status=1

чтобы получить что-то вроде

   user.id  username/message.id    email/subject 
    1        jane                   jane@gmail.com   
    2        john                   john@yahoo.com   
    3        jim                    jim@msn.com      
    1        120                    Notification           
    1        122                    Re:Hello           
    1        125                    Quotation          
    2        127                    Hi jane          
    2        128                    Fix thiss           
    2        129                    Ok          
    3        140                    Re:Re:Quotation

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

Но сэкономленный сетевой трафик редко стоит дополнительной сложности.

...