Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > СУБД, общие вопросы > оптимизация запроса


Автор: Vidocq 11.4.2006, 19:09
Есть запрос smile
Код

select  ls.name as servername, lst.name as platform, lsi.ip as serverip,
        (select count(l_server_id) from l_server_ips where l_server_id=ls.id) as totalips,
        (select count(l_server_id) from l_server_ips where l_server_id=ls.id and flag!=0) as ips_used,
        (select count(l_server_id) from l_server_ips where l_server_id=ls.id)-(select count(l_server_id) from l_server_ips where l_server_id=ls.id and flag!=0) as ips_free,
        cast((select count(l_server_id) from l_server_ips where l_server_id=ls.id and flag!=0) as real)/(select count(l_server_id) from l_server_ips where l_server_id=ls.id)*100 as ips_used_percent,
        ls.signup as signup
        from l_server ls
        join l_server_types lst on ls.type_id=lst.id
        join l_server_groups lsg on (ls.group_id=lsg.id and (lsg.name='web servers' or lsg.name='win servers'))
        join l_server_ips lsi on (ls.id=lsi.l_server_id and lsi.flag=2)


Но работает очень долго. Как его можно оптимизировать?

Автор: LSD 11.4.2006, 19:23
СУБД какая?

Автор: Vit 11.4.2006, 19:46
Vidocq, стыдно! Вы же не новичёк на форуме, а такой простой вещи как прочитать правила раздела в рамочке не соизволили! Пока только устное предупреждение, следующий раз такие сообщения будут идти сразу в корзину!

Автор: chief39 11.4.2006, 20:24
Цитата(LSD @ 11.4.2006, 19:23 Найти цитируемый пост)
СУБД какая?

Глаголеть мне моя интуиция, что это сибэйс или М$ smile

Vidocq, Вроде никак. Сам текст. Надо будет ещё раз на свежую голову взглянуть.
Индексы неплохо бы создать, если их нет. По айдишкам, и юзаемым полям в условиях.
И поглядеть план запроса.
Хотя сервер и не дурак... но мало ли... если он соберёт всё в кучу - получит баальшой датарет, а потом начнёт выискивать по текстовым полям нэймы групп - будет долго smile текст савнить - это не число smile
А реально такую ситуацию как-то наблюдал smile

Автор: Vidocq 12.4.2006, 09:52
Vit,
Прошу прощения. Постил после рабочего дня, голова совсем глупая была.

База данных: Postgres 8.0.4
Способ доступа: PEAR, если правильно понял.
Среда программирования: php 5.1.2

Автор: chief39 12.4.2006, 10:32
Цитата(Vidocq @ 12.4.2006, 09:52 Найти цитируемый пост)
База данных: Postgres 8.0.4

Мдя.. не угадал smile
Глядел планы запросов?

Автор: Vidocq 12.4.2006, 11:22
Код



QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------
 Hash Join  (cost=8.06..1975.69 rows=19 width=75)
   Hash Cond: ("outer".l_server_id = "inner".id)
   ->  Seq Scan on l_server_ips lsi  (cost=0.00..1966.85 rows=109 width=20)
         Filter: (flag = 2)
   ->  Hash  (cost=8.01..8.01 rows=19 width=55)
         ->  Hash Join  (cost=2.19..8.01 rows=19 width=55)
               Hash Cond: ("outer".group_id = "inner".id)
               ->  Hash Join  (cost=1.02..6.05 rows=110 width=51)
                     Hash Cond: ("outer".type_id = "inner".id)
                     ->  Seq Scan on l_server ls  (cost=0.00..3.10 rows=110 width=37)
                     ->  Hash  (cost=1.02..1.02 rows=2 width=14)
                           ->  Seq Scan on l_server_types lst  (cost=0.00..1.02 rows=2 width=14)
               ->  Hash  (cost=1.17..1.17 rows=2 width=4)
                     ->  Seq Scan on l_server_groups lsg  (cost=0.00..1.17 rows=2 width=4)
                           Filter: ((name = 'web servers'::character varying) OR (name = 'win servers'::character varying))
   SubPlan
     ->  Aggregate  (cost=966.28..966.28 rows=1 width=4)
           ->  Index Scan using l_server_ips_ref on l_server_ips  (cost=0.00..963.65 rows=1050 width=4)
                 Index Cond: (l_server_id = $0)
     ->  Aggregate  (cost=968.61..968.61 rows=1 width=4)
           ->  Index Scan using l_server_ips_ref on l_server_ips  (cost=0.00..966.28 rows=932 width=4)
                 Index Cond: (l_server_id = $0)
                 Filter: (flag <> 0)
     ->  Aggregate  (cost=966.28..966.28 rows=1 width=4)
           ->  Index Scan using l_server_ips_ref on l_server_ips  (cost=0.00..963.65 rows=1050 width=4)
                 Index Cond: (l_server_id = $0)
     ->  Aggregate  (cost=968.61..968.61 rows=1 width=4)
           ->  Index Scan using l_server_ips_ref on l_server_ips  (cost=0.00..966.28 rows=932 width=4)
                 Index Cond: (l_server_id = $0)
                 Filter: (flag <> 0)
     ->  Aggregate  (cost=968.61..968.61 rows=1 width=4)
           ->  Index Scan using l_server_ips_ref on l_server_ips  (cost=0.00..966.28 rows=932 width=4)
                 Index Cond: (l_server_id = $0)
                 Filter: (flag <> 0)
     ->  Aggregate  (cost=966.28..966.28 rows=1 width=4)
           ->  Index Scan using l_server_ips_ref on l_server_ips  (cost=0.00..963.65 rows=1050 width=4)
                 Index Cond: (l_server_id = $0)
(37 rows)

Мне это мало что говорит smile

Автор: Ortega 25.4.2006, 21:00
Цитата(chief39 @  11.4.2006,  20:24 Найти цитируемый пост)
получит баальшой датарет, а потом начнёт выискивать по текстовым полям нэймы групп - будет долго smile текст савнить - это не число

Действительно, попробуй поиграться с порядком join'ов. В зависимости от того, сколько обрежет проверка по группам, помести ее либо в начало (если бОльшую часть либо очень много) либо в конец (в другом случае).
Кстати, заметил еще одну вещь у тебя: примерно в половине вложенных запросов ты используешь кусок 
Код

from l_server_ips where l_server_id=ls.id and flag!=0
 
и в то же время в общем запросе ты накладываешь условие 
Код

lsi.flag=2
 то есть во вложенных запросах ты выбираешь много лишнего. Вывод: если есть возможность изменить запрос, используй
Код

from l_server_ips where l_server_id=ls.id and flag=2
 

Автор: igon 26.4.2006, 07:56
В Oracle я бы попробовал так:
Код

Select a.id, a.ips_used + a.ips_not_used totalips, a.ips_used, a.ips_not_used, a.ips_used*100/(a.ips_used + a.ips_not_used) ips_used_percent
  From (select  ls.id, Sum(Case When flag>0 Then 1 Else 0 End) ips_used, Sum(Case When flag>0 Then 0 Else 1 End) ips_not_used 
          From l_server ls, l_server_ips lsi
          Where ls.id=lsi.l_server_id
          Group By ls.id) a

Этот Select можно оформить в виде View или прямо так добавить в виде еще одного Join.
Работать вроде должно быстрее, но на массивных данных не проверял.
А вот как это все в Postgre должно выглядеть -  smile 
 

Автор: madFobos 2.5.2006, 23:58
А ты индексы используешь? 

Автор: Akina 3.5.2006, 09:25
У тебя постоянно фигурирует
Код
(select count(l_server_id) from l_server_ips where l_server_id=ls.id)
и
Код
(select count(l_server_id) from l_server_ips where l_server_id=ls.id and flag!=0)
Может имеет смысл сделать группированную выборку как еще один связанный источник?
Код

select ...
from ...
join ...
join (select l_server_id, flag, count(l_server_id) as clsi from l_server_ips group by l_server_id, flag) lsx on ls.id=lsx.l_server_id
  

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)