Итак, у меня есть таблица с 1000 строками, я просто говорю select * from hugedata limit 1
план запроса просто говорит table scan
затем limit operator
прилагается план запроса
[
{
"Plan": {
"Node Type": "Limit",
"Parallel Aware": false,
"Async Capable": false,
"Startup Cost": 0.00,
"Total Cost": 0.02,
"Plan Rows": 1,
"Plan Width": 41,
"Actual Startup Time": 0.007,
"Actual Total Time": 0.007,
"Actual Rows": 1,
"Actual Loops": 1,
"Output": ["pk", "description", "flags"],
"Shared Hit Blocks": 1,
"Shared Read Blocks": 0,
"Shared Dirtied Blocks": 0,
"Shared Written Blocks": 0,
"Local Hit Blocks": 0,
"Local Read Blocks": 0,
"Local Dirtied Blocks": 0,
"Local Written Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0,
"WAL Records": 0,
"WAL FPI": 0,
"WAL Bytes": 0,
"Plans": [
{
"Node Type": "Seq Scan",
"Parent Relationship": "Outer",
"Parallel Aware": false,
"Async Capable": false,
"Relation Name": "hugedata",
"Schema": "public",
"Alias": "hugedata",
"Startup Cost": 0.00,
"Total Cost": 15406.01,
"Plan Rows": 1000001,
"Plan Width": 41,
"Actual Startup Time": 0.006,
"Actual Total Time": 0.006,
"Actual Rows": 1,
"Actual Loops": 1,
"Output": ["pk", "description", "flags"],
"Shared Hit Blocks": 1,
"Shared Read Blocks": 0,
"Shared Dirtied Blocks": 0,
"Shared Written Blocks": 0,
"Local Hit Blocks": 0,
"Local Read Blocks": 0,
"Local Dirtied Blocks": 0,
"Local Written Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0,
"WAL Records": 0,
"WAL FPI": 0,
"WAL Bytes": 0
}
]
},
"Settings": {
},
"Planning": {
"Shared Hit Blocks": 0,
"Shared Read Blocks": 0,
"Shared Dirtied Blocks": 0,
"Shared Written Blocks": 0,
"Local Hit Blocks": 0,
"Local Read Blocks": 0,
"Local Dirtied Blocks": 0,
"Local Written Blocks": 0,
"Temp Read Blocks": 0,
"Temp Written Blocks": 0
},
"Planning Time": 0.035,
"Triggers": [
],
"Execution Time": 0.069
}
]
Вопрос в том, как применяется ограничение в postgres?
ИЛИ
Судя по моему поиску, оператор ограничения работает так, как было предложено в первом пункте, если это правда, то почему такая неэффективная реализация, или я что-то упускаю?
В документации по ограничениям говорится, что при создании плана запроса учитывается ограничение, но дает ли он результат в строке N+1 или «учтено» означает, что что-то еще не указано... https://www.postgresql.org/docs/ текущий/queries-limit.html
«Мой поиск» — это план объяснения, в котором говорится, что дочерние узлы выполняются первыми, немногие люди, с которыми я разговаривал, говорят, что это всегда неэффективно по сравнению с использованием предложенияwhere между числовыми pk и ChatGPT.
Беги explain analyze select * from hugedata limit 1
limit
без order by
— это своего рода случайный результат. Вряд ли вы этого хотите. Утверждения этих немногих людей, которых вы упомянули, не подтверждаются никакими планами запросов и поведением базы данных, и их мнение невозможно проверить.
@FrankHeikens Адриан Клавер Мне действительно интересно узнать, что происходит на самом деле, независимо от мнения других людей, так что игнорируйте это… какой из них 1 или 2? и какие доказательства у нас есть, чтобы поддержать это?
Пожалуйста, поделитесь своим планом запроса, используя explain(analyze, verbose, buffers, settings)
для оператора SQL. В текстовом виде, пожалуйста, как обновление вашего вопроса.
@FrankHeikens, обновил его со всеми параметрами. Глядя на план, кажется, что на этапе планирования все строки 1000001 назначаются для чтения запросом, но когда происходит выполнение, он считывает только 1 строку, то есть: фактическое количество строк является правильной интерпретацией. ?
Как видите, он останавливается после 1 ряда. Выполнение занимает всего 0,069 миллисекунды.
Исполнитель PostgreSQL работает по требованию и сверху вниз.
Чтобы вычислить первую строку результата, она извлекает первую строку из узла Limit
. Это, в свою очередь, извлекает первую строку из Seq Scan
.
Когда PostgreSQL извлекает вторую строку результата из узла Limit
, ему сообщается, что выполнение завершено.
в итоге при последовательном сканировании извлекается только одна строка.
Вы можете найти это в README исполнителя:
Исполнитель обрабатывает дерево «узлов плана». Дерево плана по существу конвейер по требованию операций обработки кортежей. Каждый узел, когда вызывается, создаст следующий кортеж в своей выходной последовательности или NULL, если нет доступно больше кортежей. Если узел не является примитивным сканированием отношений узел, у него будут дочерние узлы, которые он, в свою очередь, вызывает для получения входных данных. кортежи.
Любые ссылки на документы, подтверждающие это, кроме плана выполнения...
Я добавил ссылку на исходную документацию.
From my search
... на самом деле вы не предоставляете никаких подробностей своего поиска, но он явно пытается сделать что-то вроде #2. Это не всегда возможно, конечно.