IMHO.WS

IMHO.WS (http://www.imho.ws/index.php)
-   Программирование (http://www.imho.ws/forumdisplay.php?f=40)
-   -   SQL запросы (http://www.imho.ws/showthread.php?t=107737)

kogan 30.08.2006 23:32

SQL запросы
 
Обсуждение запросов на SQL и проблем с ними.

начну с бонального и распространенного:

есть две связаные таблицы -
users
__________________________
id | name | vozrost | profesia
------------------------------
1 | Федя | 21 год | 2
2 | Нина | 18 лет | 3
3 | Гена | 24 года| 5

t_profesia
__________________________
id | prof_name
------------------------------
1 | Программист
2 | Строитель
3 | Доктор
4 | Артист
5 | Учитель

Вопрос - как составить запрос чтоб результат был таков:
__________________________
id | name | vozrost | profesia
------------------------------
1 | Федя | 21 год | Строитель
2 | Нина | 18 лет | Доктор
3 | Гена | 24 года| Учитель

EvroStandart 31.08.2006 10:44

А в какой программе?

В мускле должно сработать:
SELECT u.id, u.name, u.vozrost, p.prof_name FROM users AS u
LEFT JOIN t_profesia AS p ON p.id=u.profesia

_Lynx_ 31.08.2006 15:39

можно и без джойнов обойтись
SELECT id, name, vozrost, (select prof_name from t_profesia where id=u.profesia) profesia
FROM users u

uerter 31.08.2006 16:32

Цитата:

Сообщение от _Lynx_
можно и без джойнов обойтись
SELECT id, name, vozrost, (select prof_name from t_profesia where id=u.profesia) profesia
FROM users u

да но как правило то такие запросы тормозят!
такчто предыдущий вариант более подходящий

nikotano 01.09.2006 00:30

SELECT u.id, u.name, u.vozrost, p.name FROM users u, t_profesia p WHERE u.profesia = p.id

kogan 01.09.2006 10:55

Цитата:

Сообщение от nikotano
SELECT u.id, u.name, u.vozrost, p.name FROM users u, t_profesia p WHERE u.profesia = p.id

:yees: я думаю это оптимальный.

_Lynx_ 01.09.2006 11:40

Цитата:

uerter:
да но как правило то такие запросы тормозят!
такчто предыдущий вариант более подходящий
С джойнами тоже случаются тормоза на больших пересечениях

Попробовал на таблицах ~4млн. х 1млн.
Простые подсчёты:
мой вариант вариант 24 сек.
EvroStandart - 11 сек.
nikotano - 2мин.37сек.

kogan 02.09.2006 01:04

:eek: .. да ладно, на какой пралформе тестил.. ?
это серьезный момент - о скорости..

Цитата:

Сообщение от _Lynx_
С джойнами тоже случаются тормоза на больших пересечениях

Попробовал на таблицах ~4млн. х 1млн.
Простые подсчёты:
мой вариант вариант 24 сек.
EvroStandart - 11 сек.
nikotano - 2мин.37сек.

- по твоим словам, EvroStandart - самы нормальный.. запрос составил..
EvroStandart - о как.. :)

Gr@nd@d 05.09.2006 13:43

Цитата:

Сообщение от _Lynx_
С джойнами тоже случаются тормоза на больших пересечениях

На самом деле вопрос стоит так - даешь ли ты оптимизацию запроса на откуп оптимизатору движка или "тыкаешь его носом". В данном случае важно есть ли индексы по связанным полям, вес индексов, наполненность таблицы и т.п. Если данных мало или наоборот много, оптимизатор может решить что ему проще отобрать нужные значения простым перебором. В общем случае варианты nokitano и evro почти одинаковы, но у nikotano более "универсальный" - считается что оптимизатор умнее и лучше знает что ему надо ;)

kogan 06.09.2006 16:52

Цитата:

Сообщение от Gr@nd@d
На самом деле вопрос стоит так - даешь ли ты оптимизацию запроса на откуп оптимизатору движка или "тыкаешь его носом". В данном случае важно есть ли индексы по связанным полям, вес индексов, наполненность таблицы и т.п. Если данных мало или наоборот много, оптимизатор может решить что ему проще отобрать нужные значения простым перебором. В общем случае варианты nokitano и evro почти одинаковы, но у nikotano более "универсальный" - считается что оптимизатор умнее и лучше знает что ему надо ;)

- как же быть с результатами тестирования? проведенными _Lynx_
Почему "умный" отимизатор не додумался их оптимизировать и вывести равное время..? :confused:

Gunslinger 06.09.2006 17:50

Стоит отметить что запросы EvroStandart и nikotano различаються. В наведеном примере они вернут одинаковый результат. Но н-р, если не указывать професию (тоесть поставить Null) у юзера, то запрос EvroStandart его выберет, а nikotano - нет.

В любом случае более правильным подходом в таких случаях (обьединения таблиц), лучше исспользовать джоины. И не только в соображениях производительности, но и в восприятии запроса человеком. Запросы с джоинами более читабельные (особенно если нужно обьединять несколько таблиц + разнообразные условия по выборке)

yan_kos 06.09.2006 20:15

Gunslinger
Не согласен!!! запрос nikotano болиее универсальный и логически верный. Зачем нам записи пиплов без професий... ето раз.
Во вторых запросы через джоин болиее сложны в чтение
В третьих если юзать движок без внешн. ключей, таким образом ожно добавить ищо один пункт к однозначности запесей.

Madness 06.09.2006 20:55

yan_kos
А что насчет теста _Lynx_??? Полностью согласен с Gunslinger.

В vbulletin повсеместно, например, используются join. Был один запрос как у nikotano, так в новой версии mysql он стал приводить к ошибке.

nikotano 06.09.2006 23:41

Прогнал все три запроса по два раза в IBExpert.
Firebird 1.0.2.
Записей в основной таблице > 1100000, во второй ~ 350000.
Вот результаты:

nikotano
Цитата:

------ Performance info ------
Prepare time = 0ms
Execute time = 1m 5s 765ms
Avg fetch time = 0,06 ms
Current memory = 13 186 048
Max memory = 13 320 296
Memory buffers = 10 000
Reads from disk to cache = 184 898
Writes from cache to disk = 0
Fetches from cache = 4 525 077

------ Performance info ------
Prepare time = 15ms
Execute time = 45s 375ms
Avg fetch time = 0,04 ms
Current memory = 13 186 048
Max memory = 13 325 416
Memory buffers = 10 000
Reads from disk to cache = 184 898
Writes from cache to disk = 0
Fetches from cache = 4 525 077
_Lynx_
Цитата:

------ Performance info ------
Prepare time = 16ms
Execute time = 50s 937ms
Avg fetch time = 0,04 ms
Current memory = 13 178 880
Max memory = 13 325 416
Memory buffers = 10 000
Reads from disk to cache = 175 366
Writes from cache to disk = 6
Fetches from cache = 9 622 151

------ Performance info ------
Prepare time = 0ms
Execute time = 1m 11s 766ms
Avg fetch time = 0,06 ms
Current memory = 13 178 880
Max memory = 13 325 416
Memory buffers = 10 000
Reads from disk to cache = 175 366
Writes from cache to disk = 6
Fetches from cache = 9 622 151
EvroStandart
Цитата:

------ Performance info ------
Prepare time = 0ms
Execute time = 1m 6s 875ms
Avg fetch time = 0,06 ms
Current memory = 13 177 856
Max memory = 13 325 416
Memory buffers = 10 000
Reads from disk to cache = 175 271
Writes from cache to disk = 0
Fetches from cache = 9 621 045

------ Performance info ------
Prepare time = 16ms
Execute time = 46s 297ms
Avg fetch time = 0,04 ms
Current memory = 13 177 856
Max memory = 13 325 416
Memory buffers = 10 000
Reads from disk to cache = 175 271
Writes from cache to disk = 0
Fetches from cache = 9 621 045
Система:
Windows XP Prof
Intel P4 2.4 GHz, 512RAM.

Цитата:

kogan:
Но н-р, если не указывать професию (тоесть поставить Null) у юзера, то запрос EvroStandart его выберет, а nikotano - нет.
Это решается при помощи внешнего ключа.

Gr@nd@d 07.09.2006 11:17

Цитата:

Сообщение от kogan
- как же быть с результатами тестирования? проведенными _Lynx_ Почему "умный" отимизатор не додумался их оптимизировать и вывести равное время..? :confused:

Потому! Это зависит от нескольких параметров:
какие данные задействованы в тесте (наполненность таблиц)
что за сервер - оптимизаторы "умные" поразному, одни больше, другие меньше ;)
Какие ключи/индексы есть и в каком состоянии.
И т.п.
Я имел ввиду, что при равных условиях результаты будут близки.
Но один "универсальнее" - больше дает свободы оптимизатору, соответственно переносимее с платформы на платформу и менее зависит от данных и структуры.

PS: Погляди на среднее время фетча в предыдущем письме...

Gunslinger 07.09.2006 12:03

Цитата:

yan_kos:
Не согласен!!! запрос nikotano болиее универсальный и логически верный. Зачем нам записи пиплов без професий... ето раз.
Если не надо то вместо Left join пишем inner join, и не будет здесь пиплов без професий. Тоесть всего-то меняем одно слово, а если нам вдруг понадобяться пиплы без професий, то в запросе nikotano придеться добавить еще одно условие, что менее универсально согласитесь.

Цитата:

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

nikotano:
Это решается при помощи внешнего ключа.
Всмысле?

nikotano 07.09.2006 16:57

Цитата:

Gunslinger:
Всмысле?
Внешний ключ + NOT NULL.
Неточно выразился.

Gunslinger 07.09.2006 18:13

Цитата:

nikotano:
Внешний ключ + NOT NULL.
Неточно выразился.
NOT NULL тебе не даст возможность ввести нулловое значение (и внешний ключ тут ни при чем), а иногда как раз нуловое и надо. Даже в нашем случае можно сказать, н-р, что если нулл, тогда значит професия не указана.

nikotano 08.09.2006 18:20

Цитата:

Gunslinger:
NOT NULL тебе не даст возможность ввести нулловое значение (и внешний ключ тут ни при чем), а иногда как раз нуловое и надо. Даже в нашем случае можно сказать, н-р, что если нулл, тогда значит професия не указана.
Логично.
Но я обычно вношу системную запись "Не указано" с идентификатором 0 и ставлю 0 как дефолтовое значение.

Ну это дело вкуса.

Gr@nd@d 11.09.2006 09:44

Цитата:

Сообщение от Gunslinger
Если не надо то вместо Left join пишем inner join, и не будет здесь пиплов без професий. Тоесть всего-то меняем одно слово, а если нам вдруг понадобяться пиплы без професий, то в запросе nikotano придеться добавить еще одно условие, что менее универсально согласитесь.

Позволь не согласиться.
Как раз условия в запросе более универсальны при переносе между разными платформами/версиями/и т.п.
Кроме того куча софта, использующего QBE умеет парсить/модифицировать именно условия.
Ну и кроме прочего, говоря join ты указываешь оптимизатору что к чему цепляется (left\right join). Что в общем случае не универсально.

PS: заметь - я не говорю, что join это плохо, сам пользуюсь ;) но речь о универсальности идет, а это другая песня...

Gunslinger 11.09.2006 10:41

Цитата:

Gr@nd@d:
Позволь не согласиться.
Как раз условия в запросе более универсальны при переносе между разными платформами/версиями/и т.п.
Кроме того куча софта, использующего QBE умеет парсить/модифицировать именно условия.
Ну и кроме прочего, говоря join ты указываешь оптимизатору что к чему цепляется (left\right join). Что в общем случае не универсально.
Я вот всегда думал что джоины - это стандарт ANSI, а значит должен поддерживаться всемя платформами/версиями/и т.п. или это не так?

FACE CONTROL 11.09.2006 16:12

Подскажите пожалуйста, с чего можно и нужно начать изучать SQL, :idontnow: заранее спасибо! :help:

nikotano 11.09.2006 17:18

Цитата:

Myp3uk:
Подскажите пожалуйста, с чего можно и нужно начать изучать SQL, :idontnow: заранее спасибо! :help:
Мартин Грубер. Понимание SQL.
Книга просто супер (вышла в 93 году).
Можно пользоваться и как учебником, и как справочником.
Поищи в Интернете. Должна быть.

Gr@nd@d 12.09.2006 06:24

Цитата:

Сообщение от Gunslinger
Я вот всегда думал что джоины - это стандарт ANSI, а значит должен поддерживаться всемя платформами/версиями/и т.п. или это не так?

Так-то оно так, и поддерживается всеми, только вот "диалекты" бывают разные. Сталкивался я пару раз с тем, что чисто синтаксически написание отличается. А вот с WHERE ни разу проблем не было ;)

kogan 18.09.2006 18:39

..?
 
Ладно терь все это знают, а как быть если нужно выбрать разные записи с разных таблиц да еще и с нескольких баз ЗА ОДНО обращение к базе (один запрос) ??? :confused:
(для Mysq)

Gr@nd@d 19.09.2006 06:05

Цитата:

Сообщение от kogan
Ладно терь все это знают, а как быть если нужно выбрать разные записи с разных таблиц да еще и с нескольких баз ЗА ОДНО обращение к базе (один запрос) (для Mysq)

За мыскль не поручусь, но в нормальных серверах запросы к разным таблицам интегрируются либо через UNION, если структура одинакова или ее можно "усреднить", либо хранимыми процедурами. Ну бывают еще варианты с представлениями (VIEW).
Что касаемо запросов к разным базам, то обычно для серверов, где понятие "база" существует, такие штуки решаются многозвенкой, а где не существует - поддерживается самим сервером...

Alex Dark 22.01.2009 12:22

Проблемма:
Есть прога, к базе данных которой я могу подключиться при помощи ibExpert (установился с прогой, есть логин, пароль). Где что храниться в базе разобрался сам. Необходимо в одну из таблиц периодически добавлять несколько записей. В ручном режиме сделать это могу.
Хотелось бы автоматизировать процесс.
1 Я не знаю где, в каком разделе можно писать скрипты и как их сохранить
2 Сам скрипт.
таблица comment. поля cart (числовое) и dDate (дата-время) остальные не важны

Сначала надо выбрать данные за какой то период по полю dDate и по полю cart=3. Сделать копию этих данных и заменить поле cart на значение 4. Остальные поля соответственно оставить как в источнике.

Подсобите плиз

Gr@nd@d 23.01.2009 11:07

Цитата:

Сообщение от Alex Dark (Сообщение 1627233)
Необходимо в одну из таблиц периодически добавлять несколько записей. 1 Я не знаю где, в каком разделе можно писать скрипты и как их сохранить 2 Сам скрипт.
таблица comment. поля cart (числовое) и dDate (дата-время) остальные не важныСначала надо выбрать данные за какой то период по полю dDate и по полю cart=3. Сделать копию этих данных и заменить поле cart на значение 4. Остальные поля соответственно оставить как в источнике.

Непонятно что за база, ибо ibexpert с разными работать может.
Предположу, что это interbase/firebird.

Тогда по второму вопросу - запрос выглядит примерно так:
Код:

INSERT INTO COMMENT(CART,DDATE,остальные поля)
SELECT 4,DDATE,остальные поля FROM COMMENT WHERE
(COMMENT.CART = 3) AND (COMMENT.DDATE BETWEEN :D1 AND :D2)

где D1 и D2 - параметры или значения дат нужного периода

По первому вопросу сложнее - скрипты как правило это обычные текстовые файлы. Другое дело как их выполнять - в самой базе нет самоисполняемых механизмов. Все действия инициируются извне какой-либо программой. Например консольной утилитой ISQL входящей в состав firebird, или ibexpert`ом, или твоей прикладной программой. В составе ibexpert`а есть утилита ibscript, можно попробовать ее зашедулить.
А если в базе есть хранимые процедуры или триггеры, которые периодически вызываются твоей программой, можно включить этот запрос туда. Вот только запрос у тебя с параметрами получается... Нужно либо вычислять эти параметры "на лету", либо передавать их. ну и наконец можно просто скидать небольшую программку которая будет выполнять нужные тебе действия. Это в общем. Более конкретные рекомендации требуют более конкретного изучения вопроса.


Часовой пояс GMT +4, время: 03:26.

Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.