Postgresql: пустой ответ на запрос при наличии записей: сбой или есть причина?
Имеется таблица с набором записей. Приложение даёт запрос в эту таблицу по определённому условию и получает результат. В какой-то момент происходит странное: запрос, который должен гарантированно вернуть набор строк, возвращает пустой курсор. Был восстановлен архив БД на момент инцидента, исследования и анализ значений primary-ключа и timestamp-метки показали, что в момент выполнения запроса в таблице были записи, удовлетворяющие условию. И есть лог-запись с текстом запроса и результатом - 0 записей! И этот же запрос на восстановленном архиве возвращает записи, подтверждая, что записи должны были быть найдены. Но в логе сказано - 0 записей.
Вопрос: при каких условиях Postgresql может вернуть пустой результат при фактическом наличии соответствующих запросу записей? Сбой, особенности, о которых мне неизвестно, руки кривые, что-то ещё...
В связи с советом Vitsliputsli, думаю следующее. Никаких манипуляций с искомыми записями не производилось в течение года. Это значит, что:
- если бы искомые записи застряли в кэше, а postgresql не определил бы, что кэш инвалидный, и продолжал бы его использовать, запрос вернул бы эти записи.
- если бы postgresql понял, что кэш устарел, он запросил бы их заново из таблицы, и тоже вернул бы их.
Получается, что независимо от состояния кэша, запрос должен был вернуть непустой результат. А он пустой. И произошло это внезапно, только один раз, и никак не воспроизводится. И что делать? Списать на сбой postgresql, или есть разумная причина такого явления?
Vitsliputsli, а что именно копать? Да и дело в том, что записи, которые должны были быть возвращены, находились там без изменений с апреля 2018 года, т.е. уже год. Значит, и в кэше, если он "застарел", они тоже должны были быть. Так что вряд ли эта проблема в кэше.
Алексей, и тем не менее, на вашем месте лучше проверить, а не полагаться на "вряд ли". Срок не имеет значения, бывает и год могут данные выдаваться из кеша при некорректных настройках, когда сервер не определяет, что кеш инвалиден.
Просто отключите кеширование данных запросов и посмотрите на результат.
Алексей, с кешированием есть ещё момент, кешируются данные для конкретного запроса, т.е. достаточно изменить запрос, чтобы он выдавал то же самое, но выглядит он для сервера как новый, и он отработает без кеша. Можете так проверить.
Vitsliputsli, согласен с вами, но проблема в том, что я не могу воспроизвести эту ситуацию с отключенным кэшем, т.к. а) ситуация была на боевом сервере, где собственно кэш, а я тестирую на dev, и б) ситуация была в прошлом, т.е. 2 недели назад. Сейчас всё что есть - это архив БД на момент инцидента. И потом, я не вижу, как именно кэш мог повлиять на ответ. Если бы запрос вернул строки из кэша, а их реально в таблице уже не было - это понятно, можно грешить на кэш. Но запрос не вернул записей. И тогда у меня возникает вопрос: а в принципе мог кэш ответить, что записей нет, хотя они там были?
Да и кеширование не очень хочется отключать. Такое произошло впервые за много лет, и неизвестно, произойдёт ли ещё раз. Но хочется понять причину.
если бы postgresql понял, что кэш устарел, он запросил бы их заново из таблицы
Мне очень интересно, где вы в postgresql нашли кэш запросов.
Нет его, никогда не было и не будет. В mysql - единственной мне известной СУБД где когда-то был кэш запросов - его уже тоже нет.
Ну а если вы про внешний кэш говорите - то откуда бы базе узнать, что тот протух?
Melkij, select version:
PostgreSQL 9.5.14 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609, 64-bit
Я не очень глубокий знаток postgresql, поэтому не буду спорить по поводу наличия кэша запросов. Если верить информации из соотв. форумов, то postgres кэширует только данные и индексы. Но что бы он там не кэшировал, я не могу связать случившееся с работой кэша, у меня в голове цепочка не укладывается. Хотелось бы услышать от специалистов конкретный сценарий: что (по шагам) могло привести к такому поведению системы?
Melkij, нигде, была только мысль поискать в этом направлении, т.к. очень похожее поведение. Еще как минимум Oracle может кешировать результаты запросов.
Алексей, у вас странное понимание о кеше, кешируется весь ответ, а не строчки.
Информации мало, но проверьте внимательнее, возможно между запросом и ответом от базы данных стоит еще какой то код, может в нем ошибка?
Я бы добавил отладочную информацию прямо в код где идет ответ от базы данных по условию используемого sql, и пишите в лог дату, параметры запроса и количество записей в результате. По результатам сможете хотя бы гарантировать что это база данных глючит.
Проверьте сетевое соединение до базы данных, особенно если она находится на другом сервере, правда в этом случае у вас должна приходить ошибка, но очень часто бывает программисты ленятся проверять все случаи (типа если предыдущий вызов без ошибок то зачем проверять следующий).
Запустите утилиты проверки целостности базы данных и файловой системы. Банально проверьте работоспособность железа, вдруг у вас оперативная память глючит (правда у вас вылезало бы еще много где косяков) или сбоит контроллер жесткого диска (смотрите логи сервера dmesg хотя бы).
Проверял код между запросом и ответом от базы данных, ничего подозрительного.
> Я бы добавил отладочную информацию прямо в код...
Система пишет расширенный лог постоянно, это её нормальное состояние, и в этом логе и дата, и текст запроса "как есть", и количество записей в ответе. Именно это и помогло выполнить анализ происходящего, впрочем, безуспешно.
БД и приложение на одном сервере, сетевой ошибки не должно быть.
С файловой системой и БД всё в порядке, утилиты отработали без ошибок. В логах тоже ничего подозрительного.
Уже весь мозг вывихнул. И ещё нюанс: на самом деле приложение выполняет два запроса с перерывом в несколько минут. Первый запрос проверяет наличие этих записей, и если их нет - позволяет юзеру выполнить некоторые действия. Второй запрос - контрольный, и он внешне отличается от первого, но по сути также проверяет наличие этих записей (вдруг их кто-то добавил, пока юзер копался на сайте). Перед вторым запросом выполняется блокировка таблиц. И вот обе эти проверки не сработали, будто на несколько минут эти записи стали невидимыми.
Это работает уже много лет, никогда ничего подобного не происходило, поэтому я не склонен думать, что это архитектурная ошибка приложения. Но в то же время я не представляю, как такое в принципе возможно в postgresql.
rPman, железо в порядке. Да и сервер - это VDS на хостинге провайдера, там и без меня следят за этим. Если бы был сбой, который потом провайдер оперативно поправил, тогда бы в логах остались следы. Их нет. Мистика, короче...
exectime=0.005206
rows=0
SELECT room_id, type, count(CASE WHEN not upperplace THEN 1 END) AS amount, count(CASE WHEN upperplace THEN 1 END) AS up_amount FROM u5.t5_room_occupied WHERE '2019-06-17T08:00:00'::timestamp <= dep_date AND entry_date <= '2019-06-20T09:00:00'::timestamp AND apartment_id=35 AND NOT (tour_id <> 8296 AND tour_lock) GROUP BY room_id, type
Хотя, признаться, не понимаю, что это может вам дать...
ума не приложу почему база данных вам периодически выдает не те значения, в тему проблем с индексами еще вариант такой - пересоздать все индексы (ну или только те что используются в этих запросах для скорости)
p.s. чуйкой чую нет ли в этих count case when какой то проблемы? я правильно понимаю вы так считаете количество true и false значений upperplace, одним запросом! в документации пишут надо использовать filter
а если разделить на два запроса, проблема исчезает?