2016-06-06 4 views
1

Я написал запрослогика изменение существует против существует предел 1

select * from table 
where exists (select 1 from table1 where table.column = table1.column) 

Если я изменю его к

select * from table 
where exists (select 1 from table1 where table.column = table1.column limit 1) 

это Изменился ли логика?

Я спрашиваю, была ли изменена стоимость запроса плана (17000 -> 2400). I с использованием Postgres 9.4

обновление: объяснить анализ многословным двух запросов

explain (analyze, verbose) 
select * from sr_srv_rendered r 
where exists (select 1 from sr_res_group rg where rg.id = r.res_group_id and rg.responsible_id = 1) 

limit 30 

"Limit (cost=62.06..74.63 rows=30 width=157) (actual time=0.017..0.017 rows=0 loops=1)" 
" Output: r.id, r.bdate, r.comment, r.cost, r.duration, r.edate, r.is_rendered, r.quantity, r.total_cost, r.contract_id, r.customer_id, r.funding_id, r.res_group_id, r.service_id, r.duration_measure_unit_id, r.begin_time, r.prototype_id, r.org_id, r.price_ (...)" 
" -> Nested Loop (cost=62.06..287707.96 rows=686607 width=157) (actual time=0.017..0.017 rows=0 loops=1)" 
"  Output: r.id, r.bdate, r.comment, r.cost, r.duration, r.edate, r.is_rendered, r.quantity, r.total_cost, r.contract_id, r.customer_id, r.funding_id, r.res_group_id, r.service_id, r.duration_measure_unit_id, r.begin_time, r.prototype_id, r.org_id, r. (...)" 
"  -> Bitmap Heap Scan on public.sr_res_group rg (cost=61.62..10093.63 rows=2734 width=4) (actual time=0.017..0.017 rows=0 loops=1)" 
"    Output: rg.id, rg.bdate, rg.edate, rg.is_system, rg.name, rg.department_id, rg.org_id, rg.responsible_id, rg.is_available_in_electronic_queue, rg.label_id, rg.ignore_regclinic_check, rg.note, rg.blocked, rg.block_comment, rg.template_res_grou (...)" 
"    Recheck Cond: (rg.responsible_id = 1)" 
"    -> Bitmap Index Scan on responsible_fk (cost=0.00..60.94 rows=2734 width=0) (actual time=0.015..0.015 rows=0 loops=1)" 
"     Index Cond: (rg.responsible_id = 1)" 
"  -> Index Scan using fkb95967dd9f6b119a on public.sr_srv_rendered r (cost=0.43..99.03 rows=251 width=157) (never executed)" 
"    Output: r.id, r.bdate, r.comment, r.cost, r.duration, r.edate, r.is_rendered, r.quantity, r.total_cost, r.contract_id, r.customer_id, r.funding_id, r.res_group_id, r.service_id, r.duration_measure_unit_id, r.begin_time, r.prototype_id, r.org_ (...)" 
"    Index Cond: (r.res_group_id = rg.id)" 
"Planning time: 0.931 ms" 
"Execution time: 0.355 ms" 





explain (analyze, verbose) 
select * from sr_srv_rendered r 
where exists (select 1 from sr_res_group rg where rg.id = r.res_group_id and rg.responsible_id = 1 limit 1) 

limit 30 

"Limit (cost=0.00..509.03 rows=30 width=157) (actual time=49392.352..49392.352 rows=0 loops=1)" 
" Output: r.id, r.bdate, r.comment, r.cost, r.duration, r.edate, r.is_rendered, r.quantity, r.total_cost, r.contract_id, r.customer_id, r.funding_id, r.res_group_id, r.service_id, r.duration_measure_unit_id, r.begin_time, r.prototype_id, r.org_id, r.price_ (...)" 
" -> Seq Scan on public.sr_srv_rendered r (cost=0.00..100177996.03 rows=5904050 width=157) (actual time=49392.340..49392.340 rows=0 loops=1)" 
"  Output: r.id, r.bdate, r.comment, r.cost, r.duration, r.edate, r.is_rendered, r.quantity, r.total_cost, r.contract_id, r.customer_id, r.funding_id, r.res_group_id, r.service_id, r.duration_measure_unit_id, r.begin_time, r.prototype_id, r.org_id, r. (...)" 
"  Filter: (SubPlan 1)" 
"  Rows Removed by Filter: 11062881" 
"  SubPlan 1" 
"   -> Limit (cost=0.43..8.46 rows=1 width=0) (actual time=0.004..0.004 rows=0 loops=11062881)" 
"    Output: (1)" 
"    -> Index Scan using sr_res_group_pk on public.sr_res_group rg (cost=0.43..8.46 rows=1 width=0) (actual time=0.003..0.003 rows=0 loops=11062881)" 
"      Output: 1" 
"      Index Cond: (rg.id = r.res_group_id)" 
"      Filter: (rg.responsible_id = 1)" 
"      Rows Removed by Filter: 1" 
"Planning time: 0.694 ms" 
"Execution time: 49392.495 ms" 

объяснить без Params построен быстрее

+3

Это не должно изменять логику вообще. Это также не должно влиять на производительность. Для лучшей производительности вам нужен индекс в 'table1 (column)'. –

+0

Это определенно выглядит проблемой в оптимизаторе (если не ошибка). Вы должны отправить это в список рассылки Postgres. –

ответ

3

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

Что происходит, так это то, что PostgreSQL понимает и счастлив превратить первый случай (без LIMIT внутри EXISTS) в объединение вложенного цикла, а во втором случае (с LIMIT внутри EXISTS) PostgreSQL не знает, как превратить его в соединение (из-за LIMIT) и реализует его, используя наивный подход - выполнение последовательного сканирования по таблице и выполнение подзапроса для каждой строки.

PostgreSQL понимает, как работает EXISTS, и он знает, что ему нужно найти только одну строку, добавив, что «LIMIT 1» не требуется, и, как в этом случае, на самом деле оказывается вредным.

Возможно, PostgreSQL может быть улучшен, чтобы понять, что LIMIT 1 внутри EXISTS является просто шумом и не должен иметь смысла, но это увеличит время, необходимое для планирования запросов, и не сразу понятно, что такое время было бы хорошо потрачено.

Смежные вопросы