[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: Нормализация базы данных, JOIN, SELECT
Страницы: 1, 2, 3, 4, 5, 6, 7
Гость_user
Здравствуйте.
Изучаю теорию реляционных баз данных.
При нормализации баз данных (приведение к 3-м НФ) информация, естественно, разбивается на отдельные сущности - таблицы (в упрощенном, практическом понимании). При этом для получения целостного набора данных необходимо делать выборку из нескольких таблиц, а это либо множественные простые запросы (SELECT), либо "то, что доктор прописал" - JOIN'ы. И вот тут возникает частичное непонимание. С одной стороны нормализация, формально, обеспечивает более простую работу с данными, при помощи более простых запросов, а значит и более быструю (не беру варианты, когда денормализация более приемлема с точки зрения прозводительности). Но в то же время (накладываю неполную информационную картинку, которую получил с данного ресурса на новые для меня академические данные) JOIN, как не раз упоминалось здесь на сайте, является более ресурсоемкой операцией, чем просто несколько SELECT'ов. Что же все таки быстрее при работе с нормализованной базой данных: JOIN или несколько SELECT'ов. Само собой разумеется, что несколько SELECT'ов, в более или менее сложном проекте для одной операции, - это лишняя головная боль, но пока - без учета сложностей реализации. Исключительно с точки зрения нагрузки на аппаратную часть сервера.
inpost
SELECT к первой таблице, получил данные, потом SELECT ко второй таблице. Обычно 2-3 запроса, это не так уж и много.
Я бы даже сказал, что JOIN лишь упрощает код, но увеличивает нагрузку. Недавно перешел на таблицу полностью в памяти, ещё не делал замеры на новом сервере, но вот когда таблицы не были загнаны в память - скорость даже в цикле 5-6 запросов была быстрее, чем 1 запрос с JOIN по тем же индексам.

Приведу забавный пример:
SELECT *
FROM `table2`
WHERE `id` IN (SELECT `id` FROM `table1` WHERE `zzz` = 'xxx')

Итак, я запустил отдельно запрос к table1 и получил скорость выполнения ~0.05 сек (вроде достаточно быстро по индексу, просто таблица очень большая).
Дальше у таблицы №2 тоже индекс по id, результат первой выборки - 5 ID, итого WHERE `id` IN (тут 5 айдишников) - это достаточно быстрый запрос. Медленные - когда перечень этих ID более 50-100.
Так вот, этот запрос у меня повис в mysql на 60 секунд. После я его грохнул и запустил по очереди в PHP, 2 запроса отработало менее секунды.

Отсюда после запроса№1, который был тестовый на:
SELECT `id` FROM `table1` WHERE `zzz` = 'xxx'
Я получил быстрый запрос, а потом его же повторил внутри подзапроса - и очень долгая работа.

По поводу JOIN - несколько похожая схема, неожиданно простые запросы стали попадать в лимит 2 секунды на выполнение. Я специально сделал замеры каждого отдельного запроса и получил очень быструю работу, в итоге переписал на 2 отдельных SELECT.

______________________

Так вот, нормализация БД - это на моё мнение создание доступных данных, то есть у нас адекватная структура, при которой мы можем получить доступ к разным отдельным элементам. Как раз к оптимизации скорости работы относится уже денормализация этой структуры.

_____________
Обучаю веб-программированию качественно и не дорого: http://school-php.com
Фрилансер, принимаю заказы: PHP, JS, AS (видео-чаты). Писать в ЛС (Личные сообщения на phpforum).
Гость_user
Развернутый ответ, спасибо.
Гость_user
Еще вопрос в этой связи.

Модель.
Есть проект. Не статичный сайт визитка, а значит развивается и будет развиваться. Реализация - с расчетом на рост посещаемости. Изначально, при проектировании бд, используется нормализация до 3-й нормальной формы (денормализовать в последствие будет проще, при необходимости). Join'ы не используются, используются простые запросы SELECT с подзапросами. В случае, если возникает необходимость денормализации бд, как быть с запросами и подзапросами в том плане, что ранее данные собирались из разных мест составным запросом, а а теперь хранятся в одном месте и запрос упрощается до одного простого SELECT . Но запрос к данным таблицам был не один и придется их изменять везде. Можно каким-то образом абстрагироваться от этого, как-то централизовать такие обращения, чтобы необходимость изменения данных присутствовала только единожды, в одном месте? Что-то вроде представления, которое будет храниться постоянно и которое можно в любой момент изменить.
twin
Цитата (inpost @ 10.09.2013 - 00:02)
Приведу забавный пример:
SELECT *
FROM `table2`
WHERE `id` IN (SELECT `id` FROM `table1` WHERE `zzz` = 'xxx')


Этот забавный пример ничего общего не имеет с JOIN. Да, по возможности нужно избегать составных запросов, но тут дело совсем не в этом.

Просто это не два запроса. Количество запросов определяется количеством строк плюс один.

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

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


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

Нужно уважать мнение оппонета. Ведь заблуждаться - его святое право.

Настаивал, настаиваю и буду настаивать на своем. На кедровых орешках.

user posted image
sergeiss
И я тоже добавлю. Говоря о скорости выполнения запросов, надо еще смотреть насчет индексов. Вполне возможно, что просто нет одного, но важного индекса, в итоге запрос работает дольше, чем может. Но человек объясняет долгое время выполнения запроса не отсутствием индекса, а структурой запроса.

Вывод простой. Говорить о скорости выполнения (и об оптимизации запроса) имеет смысл только при обсуждении определенных запросов, а не абстрактно.
Иначе получаем сравнение типа такого: кто быстрее доберется до финиша через 100 метров: я или чемпион мира по бегу на 100 метров? Ответ не очевидный, на самом деле, если забыли учесть, что я побегу, а он поползёт smile.gif

_____________
* Хэлп по PHP
* Описалово по JavaScript
* Хэлп и СУБД для PostgreSQL

* Обучаю PHP, JS, вёрстке. Интерактивно и качественно. За разумные деньги.

* "накапливаю умение телепатии" (С) и "гуглю за ваш счет" (С)

user posted image
inpost
twin
Внимательно почитай, там идёт обсуждение про "несколько SELECT" и я дал ответ, что несколько SELECT в виде "подзапросов" - не эффективно, то есть я дал ответ в тему. + Я сказал, что отдельные несколько SELECT - уже высокая производительность.

_____________
Обучаю веб-программированию качественно и не дорого: http://school-php.com
Фрилансер, принимаю заказы: PHP, JS, AS (видео-чаты). Писать в ЛС (Личные сообщения на phpforum).
twin
Всё я правильно прочитал. ТС не имел ввиду вложенный запрос, а имел ввиду несколько отдельных запросов с обработкой результатов на стороне пыха.

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

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

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

Нужно уважать мнение оппонета. Ведь заблуждаться - его святое право.

Настаивал, настаиваю и буду настаивать на своем. На кедровых орешках.

user posted image
twin
MiksIr
Цитата
JOIN как правило не должен быть медленее, чем выборка двух таблиц по отдельности + время на их объединение в приложении.
Тут дело не в общем времени, а именно суммарном времени запросов. Дабы не создавать очередь в СУБД. Конечно обработка в скрипте будет медленнее, но там многопоточность.

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

Нужно уважать мнение оппонета. Ведь заблуждаться - его святое право.

Настаивал, настаиваю и буду настаивать на своем. На кедровых орешках.

user posted image
twin
Да многопоточна, это понятно. Не в том дело. Просто таблица лочится на дольше, если выполняется JOIN, чем два последовательных SELECT. Когда нагрузка большая, эта разница может оказаться довольно существенной. А при двух селектах время "склеивания" переносится на сторону PHP, а там очереди не бывает.

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

Нужно уважать мнение оппонета. Ведь заблуждаться - его святое право.

Настаивал, настаиваю и буду настаивать на своем. На кедровых орешках.

user posted image
Arh
А если брать конкретный пример?
Допустим вывод новостей (30 штук на страницу).
SELECT `id`,`title`,`value`,`user_id` FROM news


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

SELECT n.`id`,n.`title`,n.`value`,n.`user_id`,
u.`name`,u.`surname`
FROM news n
LEFT JOIN users u ON u.`id` = n.`user_id`

или ?
SELECT `id`,`title`,`value`,`user_id` FROM news

а потом в цикле
'SELECT `name`,`surname` FROM users WHERE `id` = '.(int)$row['user_id']


_____________
Промокод предоставляет скидку на заказ домена и/или хостинга reg.ru
BFCC-3895-8804-9ED2
twin
MiksIr
Цитата
Начните уже использовать MVCC. InnoDb или Postgresql.

Дельный совет. Угу.
Цитата
- Какие шины лучше использовать, липучку или шипованые?
- Начните уже ездить на тракторе, на нем ваще не скользко.


Arh
Ну в цикле то точно нельзя. Тут как раз JOIN самое оптимальное будет. Ну а уж если приспичило двумя запросами, то IN() во втором. И собрать результаты в цикле.

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

Нужно уважать мнение оппонета. Ведь заблуждаться - его святое право.

Настаивал, настаиваю и буду настаивать на своем. На кедровых орешках.

user posted image
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.