Главная Новые темы Список тем Задать вопрос Поиск  

Форум "DataBase и SQL"


Язык запросов баз даных


 #0 Deep © 18.09.07 17:38:38 - 19.09.07 17:28:50

Эффективность SQL-запросов (в частности в Firebird)



Есть главная и подчиненные таблицы. Нужно создать выборку из главной и столбцом который отображает количество записей в подчиненной таблице.

Я вижу два варианта.
1)

    select
        DD.ID,
        DD.NAME,
        DD.NAME_SHORT,
        DD.DISTRICT_TYPE_ID,
        count(RDSD.ID) as SALARY_DOC_COUNT
    from D_DISTRICT DD
        left join R_DISTRICT_SALARY_DOC RDSD on RDSD.DISTRICT_ID = DD.ID
    group by 1, 2, 3, 4


2)
    select
        DD.ID,
        DD.NAME,
        DD.NAME_SHORT,
        DD.DISTRICT_TYPE_ID,
        (select count(RDSD.ID) from R_DISTRICT_SALARY_DOC RDSD where RDSD.DISTRICT_ID = DD.ID)
    from D_DISTRICT DD

                
Первый запрос получается неэффективен из-за большого количества полей в конструкции GROUP BY. Второй же получается для каждой записи главной таблицы КАЖДЫЙ раз фильтровать подчиненную.

Может быть есть третий (более эффективный) способ? Цитата

 #1 Mystic © 18.09.07 18:10:38

1. Некорректно сравнивать запросы, возвращающие разные данные

2. > Первый запрос получается неэффективен из-за большого количества
полей в конструкции GROUP BY.


Кто тебя так обманул?



 #2 Deep © 18.09.07 18:44:42

>  #1   Mystic ©
почему разные? у меня одинаковые
если тебя засмущал GROUP BY в первом запросе, то скажу что он реально не группирует записи в мастер таблице, потому что в группировку включен первичный ключ. GROUP BY там только для того, чтоб можно было посчитать COUNT для подчиненной таблицы.

> Кто тебя так обманул?
А разве операции группировки не считаются медленными? Особенно по полям типа varchar(200) ?

гм... или встретив первое же различие (в моем случае - по первичному ключу) остальные сервером не выполняются?

тогда запросы


select
        DD.ID, -- PK
        DD.NAME, -- varchar(200)
        DD.NAME_SHORT,
        DD.DISTRICT_TYPE_ID,
        count(RDSD.ID) as SALARY_DOC_COUNT
    from D_DISTRICT DD
        left join R_DISTRICT_SALARY_DOC RDSD on RDSD.DISTRICT_ID = DD.ID
    group by 1, 2, 3, 4


и

select
        DD.NAME, -- varchar(200)
        DD.ID, -- PK
        DD.NAME_SHORT,
        DD.DISTRICT_TYPE_ID,
        count(RDSD.ID) as SALARY_DOC_COUNT
    from D_DISTRICT DD
        left join R_DISTRICT_SALARY_DOC RDSD on RDSD.DISTRICT_ID = DD.ID
    group by 1, 2, 3, 4


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

 
 


 #3 Deep © 19.09.07 10:12:36

если исходить из того что встретив первое же различие в значениях перечня полей, которые участвуют в выражении GROUP BY (в моем случае - это различие для мастер таблицы в первом же поле, по нему построен первичный ключ) остальные сервером не выполняются, то более эффективным можно считать первый скрипт.

Правильно?
 #4 Mystic © 19.09.07 10:38:25

Отличие запросов в том, что если для некоторой записи в таблице D_DISTRICT нет записей в таблице R_DISTRICT_SALARY_DOC, то он возвращает единицу, а во втором случае нуль.

Операция группировки эквивалентна сортировке результата запросы и вычислению агрегатных функций. Для интерпретатора SQL не составляет никакой проблемы в случае наличия в в списке группировки полей, принадлежащих уникальному индексу по таблице, исключить остальные поля из сравнения. Либо использовать дополнительно ROW_GUID (вначале сравниваем ROW_GUID, если он отличается, то сравниваем поля).

Если тебя это очень парит, то сделай вьюшку:

CREATE VIEW TblStat AS SELECT ID, COUNT(*) AS Cnt FROM TblStat GROUP BY ID

и работай далее с ней:

SELECT Tbl.*, Cnd FROM Tbl LEFT JOIN TblState ON Tbl.ID = TblStat.ID
 #5 Deep © 19.09.07 12:20:21

> #4   Mystic ©
не совсем понял суть текста    
но пример меня вполне удовлетворил
так, мне кажется, действительно будет эффективнее (а заодно и нагляднее).
 #6 Mystic © 19.09.07 13:10:50


Отмодерировал:
Deep
 #7 Mystic © 19.09.07 13:12:42

Смысл был в том, что серверу оптимизировать первый запрос раз плюнуть.
 #8 Deep © 19.09.07 13:53:01

> #7   Mystic ©
ну, собственно это как раз и интересно -- откуда у тебя такая увереность в способностях сервера по оптимизации? Оно вроде как понятно, сервер писали умные люди и все такое, но где об этом можно почитать или проверить? Только опытным путем?

серверная оптимизация невидна "невооруженным" глазом, определенные выводы можно сделать исходя из плана запросов (но досконально его интерпретирвовать я пока не научился)...
в остальном же, ИМХО, оптимизация сервера остается черным ящиком    

 #9 Mystic © 19.09.07 14:34:09

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

Например, в Delphi сравнение строк сделано так: вначале сравнивает указатели. Если они совпадают, то и строки совпадают. Если не совпадают, то надо сравнивать по содержимому. Это поведение достаточно логично.

В любой DB есть понятие ROW_GUID. Это абсолюный адрес, по которому можно найти расположение строки в файле базы данных. Чтобы было легче. его можно представить как абсолютное смещение записи в фале базы данных. В Oracle эта информация доступна, в других базах данных она скрыта, но суть в том, что без этого написать хорошую базу данных нельзя.

Так вот, нам надо сравнить две записи, которые относятся к одной таблице. По сути мы имеем в терминах сервера БД следующую команду: сравнить две строки из таблицы table1 по полям ID, Name, ... Так вот, будет ли разумно первым делом сравнить ROW_GUID? А потом уже сравнивать другие поля? Ибо если они совпадут, то сравнивать остальное это мартышкин труд.

Далее, в случае, когда надо провести упорядочение строк по нескольким полям (ID, Name, ...), при этом порядок выбора не принципиален (группировка). Почему бы не вставить в это место ряд эвристик? Например, сравнение начинать с уникального ключа, а не с поля Name? Тоже я думаю, несложно реализуемо. Т. е. мы получаем, что с случае первого запроса сравнение по полям Name, NameShort выполняться не будет (с точки зрения здравого смысла)

В вообще группировка по временным затратам эквивалентна сортировке. Временные затраты O(N*Log(N)). Само вычисление агрегатных функций  есть величина порядка O(N).
 #10 Deep © 19.09.07 17:28:50

о, теперь намного понятнее!    
респект за пояснения




  • Написать ответ

    Имя: Регистрация HTML?
    smiles смайлики
    Потом перейти в:    
    паутина



      ©  webest.net, 2002-2007  

    top.mail.ru
    » Бесплатный счетчик посещений
    » Рейтинг сайтов