Объединенный Открытый Проект - Сайт для Настоящих Компьютерщиков

Объединенный Открытый Проект

Сайт для Настоящих Компьютерщиков

; Логин:
  Пароль:
Обычный
Безопасный
Запомнить пользователя



Зарегистрироваться
Забыли пароль?
 
 
 
Объединенный Открытый Проект »   Базы данных »   Об оптимизации запросов
RSS

Об оптимизации запросов

Текущий рейтинг темы: Нет

<<Назад  Вперед>>Модератор: wsxПечать
 
4X_Pro
Руководитель Проекта
Настоящий Компьютерщик
4X_Pro
Откуда: Москва
Всего сообщений: 2994
Рейтинг пользователя: 79





Дата регистрации на форуме:
29 сен. 2001
Вопрос такой: что лучше с точки зрения производительности - выполнить один запрос, извлекающий данные из кучи таблиц сразу (при этом из каждой таблицы выбирается одна запись или производится подсчет количества записей), или же последовательное выполнение нескольких запросов?
И еще: насколько сильно влияет объем извлекаемых данных на время выполнения запроса?
wsx
Модератор раздела
Юниксойд, сетевик
wsx
Откуда: Казань
Всего сообщений: 1074
Рейтинг пользователя: 28

Репутация пользователя: 1




Дата регистрации на форуме:
14 янв. 2005
Лучше всё одним запросом.
Покрайней мере это советует ANSI-SQL.
что именно хочешь оптимизировать? Не мог бы маленькую схемку нарисовать, а я что нибудь придумаю...
4X_Pro
Руководитель Проекта
Настоящий Компьютерщик
4X_Pro
Откуда: Москва
Всего сообщений: 2994
Рейтинг пользователя: 79





Дата регистрации на форуме:
29 сен. 2001
Имелось в виду следующее: насколько объем извлекаемых данных влияет на время выполнения запроса?
Я тут поэкспериментировал, и пришел к выводу, что если MySQL и скрипт - на одном компьютере - то очень незначительно (менее 1%). А вот если на разных?
А смысл вопроса такой: допустим, я хочу получить информацию о теме в форуме и о всех сообщениях в ней. Это можно сделать двумя запросами:

SELECT * FROM Topic WHERE t_id=1

SELECT * FROM Post WHERE p_tid=1


а можно одним:

SELECT * FROM Topic, Post WHERE t_id=p_tid AND t_id=1


Но во втором случае объем извлекамых из базы данных будет намного больше (т.к. данные о теме извлекаются для каждого сообщения, хотя для всех сообщений они одинаковые). Вот и хотелось бы знать, что эффективнее.
wsx
Модератор раздела
Юниксойд, сетевик
wsx
Откуда: Казань
Всего сообщений: 1074
Рейтинг пользователя: 28

Репутация пользователя: 1




Дата регистрации на форуме:
14 янв. 2005
Во первых не желаетльно использовать *, даже если нужно выбрать все поля.
Одним запросом извлекать данные более приемлемо опять же с точки зрения ANSI SQL . Но, в разных ситуациях нужно действовать по разному. Я бы вобще данный запрос переделал..

SELECT ... FROM Topic, Post WHERE Topic.t_id='xxx' AND Post.t_id='zzz';

Только я про Альясы забыл, просто вылетело из головы, как там по правельному.. Можно ещё JOINэом или CLAUSEом заюзать...
4X_Pro
Руководитель Проекта
Настоящий Компьютерщик
4X_Pro
Откуда: Москва
Всего сообщений: 2994
Рейтинг пользователя: 79





Дата регистрации на форуме:
29 сен. 2001
В том то и дело, что * я использую для расширяемости движка. Т.е. чтобы добавить, скажем, новое поле в профиль пользователя, достаточно будет в АЦ выполнить запрос для создания столбца и сделать поле для ввода в форме профиля пользователя (и в нужных местах обеспечить вывод нового поля). А так пришлось бы изменять кучу запросов...
P.S. Aliasы мне не нужны, т.к. у меня все поля называются по-разному.
wsx
Модератор раздела
Юниксойд, сетевик
wsx
Откуда: Казань
Всего сообщений: 1074
Рейтинг пользователя: 28

Репутация пользователя: 1




Дата регистрации на форуме:
14 янв. 2005
Я про другие Alias'ы... Вобщем со * переходи...
А все SQL запросы предлагаю вынести в отдельный фаил под видом переменных...
wsx
Модератор раздела
Юниксойд, сетевик
wsx
Откуда: Казань
Всего сообщений: 1074
Рейтинг пользователя: 28

Репутация пользователя: 1




Дата регистрации на форуме:
14 янв. 2005
n some cases you may wish to know which table a particular row originated from. There is a system column called tableoid in each table which can tell you the originating table:

SELECT c.tableoid, c.name, c.altitude
FROM cities c
WHERE c.altitude > 500;

which returns:

tableoid | name | altitude
----------+-----------+----------
139793 | Las Vegas | 2174
139793 | Mariposa | 1953
139798 | Madison | 845

(If you try to reproduce this example, you will probably get different numeric OIDs.) By doing a join with pg_class you can see the actual table names:

SELECT p.relname, c.name, c.altitude
FROM cities c, pg_class p
WHERE c.altitude > 500 and c.tableoid = p.oid;

which returns:

relname | name | altitude
----------+-----------+----------
cities | Las Vegas | 2174
cities | Mariposa | 1953
capitals | Madison | 845

A table can inherit from more than one parent table, in which case it has the union of the columns defined by the parent tables (plus any columns declared specifically for the child table).

A serious limitation of the inheritance feature is that indexes (including unique constraints) and foreign key constraints only apply to single tables, not to their inheritance children. This is true on both the referencing and referenced sides of a foreign key constraint. Thus, in the terms of the above example:

*

If we declared cities.name to be UNIQUE or a PRIMARY KEY, this would not stop the capitals table from having rows with names duplicating rows in cities. And those duplicate rows would by default show up in queries from cities. In fact, by default capitals would have no unique constraint at all, and so could contain multiple rows with the same name. You could add a unique constraint to capitals, but this would not prevent duplication compared to cities.
*

Similarly, if we were to specify that cities.name REFERENCES some other table, this constraint would not automatically propagate to capitals. In this case you could work around it by manually adding the same REFERENCES constraint to capitals.
*

Specifying that another table's column REFERENCES cities(name) would allow the other table to contain city names, but not capital names. There is no good workaround for this case.

These deficiencies will probably be fixed in some future release, but in the meantime considerable care is needed in deciding whether inheritance is useful for your problem.
4X_Pro
Руководитель Проекта
Настоящий Компьютерщик
4X_Pro
Откуда: Москва
Всего сообщений: 2994
Рейтинг пользователя: 79





Дата регистрации на форуме:
29 сен. 2001
Насчет выенесения запросов в отдельный файл - я сам вчера об этом подумал. Впорос только в том, как это дело автоматизировать... Без этого вряд ли выйдет перенести движок на другие базы.
Хотя процесс разработки такое вынесение значительно усложнит (знаю по опыту вынесения текстовых сообщений - я отлаживаю скрипт не на локали, а на отдельном компьютере с Linux, поэтому приходится грузить несколько файлов из разных каталогов по FTP, что очень "достает").
Оффтопик: Хотя, по идее, надо решить проблему сменой FTP-клиента для этих целей (сейчас я Total Commander использую).

4X_Pro
Руководитель Проекта
Настоящий Компьютерщик
4X_Pro
Откуда: Москва
Всего сообщений: 2994
Рейтинг пользователя: 79





Дата регистрации на форуме:
29 сен. 2001
Возвращаясь к изначальной теме: как выяснилось, все же существуют ситуации, когда делать несколько запросов вместо одного лучше. Если конкретно, лучше делать 2 (или более) разных запроса, если требуется посчитать статистику из двух разных таблиц.
Вот пример: есть таблицы User, UserRating и UserWarning, в которых хранятся данные о пользователе, его рейтинге и его предупреждениях соответственно (причем для отдельных пользователей записи в UserRating и UserWarning могут отсутствовать).
Если делать такой запрос:
SELECT u.*, SUM(ur.ur_value) AS u_rating, SUM(uw.uw_value) AS u_warning

FROM User u

LEFT JOIN UserRating ur ON (u.u_id=ur.uid)

LEFT JOIN UserWarning ON (u.u_id=uw.uid)

GROUP BY u_id


то получается следующее: сначала производится связывание всех трех таблиц, а только потом - группировка по u_id. В итоге получается следующее: каждой записи с конкретным u_id из User сопоставляется несколько строк из UserRating, а потом КАЖДОЙ из получившихся строк сопоставляется UserWarning! Т.е. если у нас для какого-то пользователя имеется 10 строк в таблице UserRating, и для него же имеется 20 строк в таблице UserWarning, то в итоге после связывания получается 200 строк. Хотя потом, за счет группировки, эти строки все равно сводятся к одной, на производительность это влияет очень ощутимо.
Поэтому в таких сутуациях лучше разбить зарпос на раздельных:

SELECT uid, SUM(uw_value) FROM UserWarining GROUP BY uid;

SELECT u.*, SUM(ur.ur_value) AS u_rating, SUM(uw.uw_value) AS u_warning

FROM User u

LEFT JOIN UserRating ur ON (u.u_id=ur.uid)

GROUP BY u_id


Если запрос делается для одного конкретного пользователя то самое простое - в дальнейшем "объединить" эти результаты средствами языка программирования, из которого вызывается запрос, а если для многих - то воспользоваться временными таблицами (т.е. сделать INSERT INTO tmpTable SELECT запрос_по_UserWarnng, а потом присоединить таблицу tmpTable ко второму запросу, тогда одному пользователю будет соответствовать в ней только одна запись и роста объема извлекаемых данных не произойдет).

---
Каждый человек всегда может найти, чем он может быть полезен окружающим. Проблема только в одном: слишком многие не хотят это искать.
wsx
Модератор раздела
Юниксойд, сетевик
wsx
Откуда: Казань
Всего сообщений: 1074
Рейтинг пользователя: 28

Репутация пользователя: 1




Дата регистрации на форуме:
14 янв. 2005
Да, будут проблемы с Ростом Извлекаемых данных! однако тут нужно подумать! т.к. Нужно чётко задать WHERE, верно использовать JOIN, и возможно UNION ALL... Кстати не давно вычетал чём различие UNION и UNION ALL прикольно однако :))


4X_Pro
Руководитель Проекта
Настоящий Компьютерщик
4X_Pro
Откуда: Москва
Всего сообщений: 2994
Рейтинг пользователя: 79





Дата регистрации на форуме:
29 сен. 2001
Я UNIONом не пользовался вообще, т.к. в MySQL 3 (а мануалом от него я и пользовался, когда начинал писать IntB) его по-моему не было...

---
Каждый человек всегда может найти, чем он может быть полезен окружающим. Проблема только в одном: слишком многие не хотят это искать.
wsx
Модератор раздела
Юниксойд, сетевик
wsx
Откуда: Казань
Всего сообщений: 1074
Рейтинг пользователя: 28

Репутация пользователя: 1




Дата регистрации на форуме:
14 янв. 2005
эээ...был!! в 3.23.58 - точно был! Кстати обнови ман :)) Там много вкусненького появилось ))


Вот бы VIEW'ы побыстрее в стабильной ветке...
4X_Pro
Руководитель Проекта
Настоящий Компьютерщик
4X_Pro
Откуда: Москва
Всего сообщений: 2994
Рейтинг пользователя: 79





Дата регистрации на форуме:
29 сен. 2001
Уже сделал несколько дней назад. Плюс скачал версию в CHM, а до этого у меня была в виде одного большого HTML, что крайне затрудняло ее использование.
Оффтопик: Но что меня конкретно бесит в CHM, так это отсутствие поиска, а также то, что там копирование в буфер обмена работает только с мышки

---
Каждый человек всегда может найти, чем он может быть полезен окружающим. Проблема только в одном: слишком многие не хотят это искать.
wsx
Модератор раздела
Юниксойд, сетевик
wsx
Откуда: Казань
Всего сообщений: 1074
Рейтинг пользователя: 28

Репутация пользователя: 1




Дата регистрации на форуме:
14 янв. 2005
Да уж.
Оффтопик: Да ну этот CHM, настоящии хакеры юзают DocBook :)))
<<Назад  Вперед>>Модератор: wsxПечать
Объединенный Открытый Проект »   Базы данных »   Об оптимизации запросов
RSS
Быстрый переход в раздел:


Время выполнения скрипта: 0.0395. Количество выполненных запросов: 18, время выполнения запросов 0.0219