У меня есть база данных с несколькими сотнями миллионов строк. Я запускаю следующий запрос:
select * from "Payments" as p
inner join "PaymentOrders" as po
on po."Id" = p."PaymentOrderId"
inner join "Users" as u
On u."Id" = po."UserId"
INNER JOIN "Roles" as r
on u."RoleId" = r."Id"
Where r."Name" = 'Moses'
LIMIT 1000
Когда предложение where находит совпадение в базе данных, я получаю результат через несколько миллисекунд, но если я изменю запрос и укажу несуществующее r."Name"
в предложении where, это займет слишком много времени. Я предполагаю, что PostgreSQL выполняет последовательное сканирование таблицы Payments
(которая содержит наибольшее количество строк), сравнивая каждую строку одну за другой.
Разве postgresql не достаточно умен, чтобы сначала проверить, содержит ли таблица Roles
строку с Name
'Moses'
?
В таблице Roles всего 15 строк, а в таблице Payments ~350 миллионов.
Я использую PostgreSQL 9.2.1.
Кстати, этот же запрос к той же схеме/данным занимает 0,024 мс на MS SQL Server.
Я обновлю вопрос и опубликую данные EXPLAIN ANALYZE через несколько часов.
Вот объяснение результатов анализа: http://explain.depesz.com/s/7e7
А вот конфигурация сервера:
version PostgreSQL 9.2.1, compiled by Visual C++ build 1600, 64-bit
client_encoding UNICODE
effective_cache_size 4500MB
fsync on
lc_collate English_United States.1252
lc_ctype English_United States.1252
listen_addresses *
log_destination stderr
log_line_prefix %t
logging_collector on
max_connections 100
max_stack_depth 2MB
port 5432
search_path dbo, "$user", public
server_encoding UTF8
shared_buffers 1500MB
TimeZone Asia/Tbilisi
wal_buffers 16MB
work_mem 10MB
Я запускаю postgresql на процессоре i5 (4 ядра, 3,3 ГГц), 8 ГБ ОЗУ и Crucial m4 SSD 128 ГБ.
ОБНОВЛЕНИЕ Это похоже на ошибку в планировщике запросов. По рекомендации Эрвина Брандштеттера я сообщил об этом в список рассылки ошибок Postgresql.
EXPLAIN
на explain.depesz.com и дайте ссылку на него в своем сообщении. Он запустится мгновенно. Спасибо, что включили версию PostgreSQL и полезные подробности. Еще одна вещь, которую стоит попробовать:ANALYZE
таблицы и посмотрите, улучшится ли производительность. Может быть, ваша статистика полностью отсутствует? Вы также можете увидеть это вexplain analyze
, это самая распространенная причина того, что оценки количества строк совершенно неверны. Пожалуйста, добавьте комментарий при обновлении, так как SO не отправляет уведомления об изменении вопроса. - person Craig Ringer   schedule 16.11.2012EXPLAIN ANALYZE
(или, по крайней мере,EXPLAIN
) для запроса, когда он быстрый. Вы показали, что такое план запроса проблемы. Было бы полезно увидеть, что выбирает PostgreSQL, когда имя существует, план запроса, который быстро дает результат. - person Craig Ringer   schedule 16.11.2012LIMIT
. Это случай, когда роль найдена, так как достаточно строк, чтобы удовлетворить ограничение, быстро найдено. Однако если роль не найдена, она продолжает поиск, пытаясь удовлетворить условию соединения(u."RoleId" = r."Id")
для достаточного количества строк. Pg выполняет этот запрос в странном порядке. Кажется очень странным не искать таблицу ролей сначала. Это не похоже на проблему со статистикой, поскольку все оценки количества строк соответствуют медленному плану. - person Craig Ringer   schedule 16.11.2012UNIQUE
(и, следовательно, индексаUNIQUE
) наRoles.RoleId
, если это совместимо с вашей моделью данных. Также покажите свою конфигурацию из wiki.postgresql.org/wiki/Server_Configuration и прочтите wiki.postgresql.org/wiki/Slow_Query_Questions . Меня особенно интересует вашjoin_collapse_limit
, хотя по умолчанию он должен быть достаточно высоким, чтобы не иметь значения для этого запроса. - person Craig Ringer   schedule 16.11.2012\d+
для ваших таблиц, обрезанный от ненужных столбцов, если хотите. - person Craig Ringer   schedule 16.11.2012LIMIT
для случая, когда роль не найдена? У меня есть подозрение, что это приведет к быстрому плану - сделатьLIMIT
виновником. - person Erwin Brandstetter   schedule 16.11.2012count(*)
или что-то в этом роде. - person wildplasser   schedule 17.11.2012