Как я избегаю избыточных полей данных в наборе результатов при использовании СОЕДИНЕНИЙ?

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

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

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

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

5
задан Ashkan Kh. Nazary 5 July 2010 в 05:23
поделиться

4 ответа

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

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

1
ответ дан 14 December 2019 в 18:56
поделиться

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

1
ответ дан 14 December 2019 в 18:56
поделиться

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

Первый заключается в том, что конструкция 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-сервера к вашей базе данных.

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

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

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

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

3
ответ дан 14 December 2019 в 18:56
поделиться

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

 user.id имя пользователя email message.id тема
1 джейн (скрыто) 120 Уведомление
null null null 122 Re: Здравствуйте
null null null 125 Цитата
2 Иоанна (скрыто) 127 Привет, Джейн
null null null 128 Исправить
null null null 129 Хорошо
3 джим (скрыто) 140 Re: Re: Цитата

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

Другой способ - запустить 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 джейн (скрыто)
2 Иоанна (скрыто)
3 джим (скрыто)
1120 Уведомление
1 122 Re: Здравствуйте
1 125 Цитата
2 127 Привет Джейн
2 128 Исправить
2 129 Хорошо
3 140 Re: Re: Цитата

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

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

0
ответ дан 14 December 2019 в 18:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: