Postgres: результаты запроса не соответствуют ожиданиям? - PullRequest
0 голосов
/ 20 января 2020

Я уже писал в C и VB, но я впервые с Prostgres. Я работал над своим приложением около месяца, но столкнулся с проблемой, которая поставила меня в тупик около недели.

У меня около 7000 строк в таблице под названием xyzfloats. Каждая строка содержит 3 числа с плавающей точкой (x float, y float, z float) (представление pointcloud в метрах)) В окончательной версии будет около 2,6 миллиарда строк, поэтому я пытаюсь работать с подмножеством, чтобы сэкономить время.

Моя другая таблица, xyztable4, содержит 24 000 000 строк. Каждая строка: xcell int, ycell int, points int, total float.

Первые два целых содержат индекс x, y. Я создал это, используя generate_series с перекрестным соединением

create table xyztable4(

xcell int,
   ycell int,
   points int default 0,
   total float default 0
)

insert into xyztable4 (xcell, ycell) 

select from generate_series(-1000,6000) as xcell cross join generate_series(-40,3360) as ycell;

План состоит в том, что каждый x, y в таблице с плавающей точкой помещается в небольшой квадрат со сторонами 0,05 м

Когда правильный квадрат для x и y идентифицирован, z добавляется в столбец «total», а столбец «points» увеличивается.

Вот код:

with subquery as (
     select x,y,z
     from xyzfloats)
update xyztable4
set
   points=points+1,
   total = total + subquery.z
from subquery

where xcell= floor(subquery.x/0.05) and ycell = floor(subquery.y/0.05)

Я пытался использовать приведение, но индекс был неправильным на отрицательной стороне.

Этаж дает правильный результат.

Проблема в том, что я обрабатываю только 234 строки, а не 7000.

Я думаю, что это может быть проблема с точностью числа ie могут быть некоторые обучающие цифры, которые означают, что это не совсем int. Я думал, что postgres использует целочисленное деление, как C?

Всегда обрабатывается одинаковое количество строк (234). Это добавляет 1 к каждому из столбца точек. Если я снова выполню запрос, я получу 2 в столбце точек. Так что это постоянно неправильно.

Я проверил это в небольшом масштабе. (9 рядов XYZ), и он отлично работает

1 Ответ

1 голос
/ 20 января 2020

Запрос не выполняет то, что вы ожидаете, из-за того, как UPDATE ... FROM ... работает в postgres. Вот цитата из документации :

Когда присутствует предложение FROM, в действительности происходит то, что целевая таблица присоединяется к таблицам, упомянутым в from_list, и каждый вывод Строка объединения представляет операцию обновления для целевой таблицы. При использовании FROM вы должны убедиться, что соединение создает не более одной выходной строки для каждой строки, подлежащей изменению. Другими словами, целевая строка не должна соединяться с более чем одной строкой из других таблиц. Если это так, то только одна из строк соединения будет использоваться для обновления целевой строки, но какая из них будет использоваться, трудно предсказать.
Из-за этой неопределенности ссылаться на другие таблицы только внутри подвыборов безопаснее, хотя зачастую сложнее для чтения и медленнее, чем при использовании объединения.

Необходимо убедиться, что соединение между таблица, которую вы обновляете (xyztable4), а таблица в предложении FROM создает одну строку на строку в основной таблице. Вы можете сделать это так:

with subquery as (
     select 
       floor(x/0.05) xcell,
       floor(y/0.05) ycell,
       count(z) cnt,
       sum(z) total_z
     from xyzfloats
     group by 1, 2
)
update xyztable4 
set
   points=points + subquery.cnt,
   total = total + subquery.total_z
from subquery

where xyztable4.xcell = subquery.xcell and xyztable4.ycell = subquery.ycell
...