Thread: Re: [pgsql-ru-general] порядок вставки

Re: [pgsql-ru-general] порядок вставки

From
Иван Фролков
Date:



Понедельник, 19 октября 2015, 17:04 +03:00 от "Dmitry E. Oboukhov" <unera@debian.org>:

WITH
"a" AS (
    SELECT 1 AS "col"
),
"b" AS (
    SELECT 2 AS "col"
),
"bc" AS (
    SELECT
        *
    FROM
        "a"

    UNION ALL

    SELECT
        *
    FROM
        "b"
)
INSERT INTO "table" ("col")

SELECT
    *
FROM
    "bc"
;

Вопрос: есть ли гарантия того что в таблицу "table" записи вставятся
строго в том порядке в котором они в таблице "bc" или нет?
Дело, собственно, в том, что в таблице bc нет подрядка записей...




Re: Re: [pgsql-ru-general] порядок вставки

From
"Dmitry E. Oboukhov"
Date:
> Дело, собственно, в том, что в таблице bc нет подрядка записей...

я не понял коментария

как это нет?
можно бесконечное множество раз делать select uinon all select и
порядок выдачи будет сохраняться один и тот же.

вопрос в том сохранится ли он в insert-select.


--

. ''`.                               Dmitry E. Oboukhov
: :’  :   email: unera@debian.org jabber://UNera@uvw.ru
`. `~’              GPGKey: 1024D / F8E26537 2006-11-21
  `- 1B23 D4F8 8EC0 D902 0555  E438 AB8C 00CF F8E2 6537

Attachment

Re[2]: [pgsql-ru-general] Re: [pgsql-ru-general] порядок вставки

From
Иван Фролков
Date:
> я не понял коментария
> как это нет?
Ну вот так вот нет.

> можно бесконечное множество раз делать select uinon all select и
> порядок выдачи будет сохраняться один и тот же.
Никто не обещает, что он будет таким же.

Re[2]: [pgsql-ru-general] Re: [pgsql-ru-general] порядок вставки

From
Иван Фролков
Date:
> вопрос в том сохранится ли он в insert-select.

И, кстати, а какая, собственно, разница в каком порядке будут добавлены строки?

Re: [pgsql-ru-general] Re: [pgsql-ru-general] порядок вставки

From
Andrey Asyakin
Date:
речь, видимо, идет о сохранении порядка sequence, create table test(id serial, val int,...)?

т.е., insert .. select, например, insert into test(val) select * from generate_series(1, 10), в test  будет
id | val
1  | 1
2  | 2
и т.д.

в доке по INSERT про порядок ничего нет, но с какой стати он будет отличаться от результатов селекта?

вот здесь http://www.postgresql.org/docs/9.5/static/executor.html читаем:

The executor mechanism is used to evaluate all four basic SQL query types: SELECT, INSERT, UPDATE, and DELETE. For SELECT, the top-level executor code only needs to send each row returned by the query plan tree off to the client. For INSERT, each returned row is inserted into the target table specified for the INSERT.



19 октября 2015 г., 18:03 пользователь Dmitry E. Oboukhov <unera@debian.org> написал:
> Дело, собственно, в том, что в таблице bc нет подрядка записей...

я не понял коментария

как это нет?
можно бесконечное множество раз делать select uinon all select и
порядок выдачи будет сохраняться один и тот же.

вопрос в том сохранится ли он в insert-select.


--

. ''`.                               Dmitry E. Oboukhov
: :’  :   email: unera@debian.org jabber://UNera@uvw.ru
`. `~’              GPGKey: 1024D / F8E26537 2006-11-21
  `- 1B23 D4F8 8EC0 D902 0555  E438 AB8C 00CF F8E2 6537

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)

iEYEAREDAAYFAlYlBiUACgkQq4wAz/jiZTektACg2KteogZHONRBysweT6OgEY0G
g/wAoI51UWFqvU5UeWz6Bf3MbsndtrEP
=HghK
-----END PGP SIGNATURE-----


Re: Re[2]: [pgsql-ru-general] Re: [pgsql-ru-general] порядок вставки

From
"Dmitry E. Oboukhov"
Date:
>> вопрос в том сохранится ли он в insert-select.

> И, кстати, а какая, собственно, разница в каком порядке будут добавлены строки?

в таблицу записываем произошедшие одно за другим события.
SERIAL в первичном ключе таким образом определяет какое событие было
раньше какое позже (таймстемп тоже есть, но он больше декоративный)
поэтому порядок INSERT'ов мне важен.

а тут получается что в одном SQL запросе получаем два события зараз (в
двух секциях WITH). и хочу сохранить их в нужном порядке
--

. ''`.                               Dmitry E. Oboukhov
: :’  :   email: unera@debian.org jabber://UNera@uvw.ru
`. `~’              GPGKey: 1024D / F8E26537 2006-11-21
  `- 1B23 D4F8 8EC0 D902 0555  E438 AB8C 00CF F8E2 6537

Attachment
> в таблицу записываем произошедшие одно за другим события.
> SERIAL в первичном ключе таким образом определяет какое событие было
> раньше какое позже (таймстемп тоже есть, но он больше декоративный)
> поэтому порядок INSERT'ов мне важен.
Вы поступаете неправильно, и вот почему - во-первых, такие вставки могут идти параллельно, и тогда порядок становится
совсемуж странным; во-вторых, порядок вставки при insert действительно не определен (при каком-то другом объеме данных
иположении звезд сервер может изменить план и порядок будет совсем иным); и то, что оно иногда (а то и практически
всегда)может работать так, как вам надо - не более чем совпадение. Я бы набрался наглости и посоветовал бы либо сделать
timestampне декоративным, либо ввести какой-то свое значение для упорядочивания). 

Re: [pgsql-ru-general] Re[2]: [pgsql-ru-general] Re: [pgsql-ru-general] порядок вставки

From
Андрей Зевакин
Date:
Как насчет:
WITH
"a" AS (
    SELECT 1 AS "col", 1 as part, row_number() over () as num
),
"b" AS (
    SELECT 2 AS "col", 2 as part, row_number() over () as num
),
"bc" AS (
    SELECT
        *
    FROM
        "a"

    UNION ALL

    SELECT
        *
    FROM
        "b"
)
INSERT INTO "table" ("col")

SELECT
    com
FROM
    "bc"
order by part, num;

С уважением, Андрей Зевакин.

20 октября 2015 г., 14:22 пользователь Dmitry E. Oboukhov <unera@debian.org> написал:
>> вопрос в том сохранится ли он в insert-select.

> И, кстати, а какая, собственно, разница в каком порядке будут добавлены строки?

в таблицу записываем произошедшие одно за другим события.
SERIAL в первичном ключе таким образом определяет какое событие было
раньше какое позже (таймстемп тоже есть, но он больше декоративный)
поэтому порядок INSERT'ов мне важен.

а тут получается что в одном SQL запросе получаем два события зараз (в
двух секциях WITH). и хочу сохранить их в нужном порядке
--

. ''`.                               Dmitry E. Oboukhov
: :’  :   email: unera@debian.org jabber://UNera@uvw.ru
`. `~’              GPGKey: 1024D / F8E26537 2006-11-21
  `- 1B23 D4F8 8EC0 D902 0555  E438 AB8C 00CF F8E2 6537

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)

iEYEAREDAAYFAlYmB74ACgkQq4wAz/jiZTeniQCguYM6XnhAOqxtRg9zC1icRmw7
+YIAnjmLepTZJ046FRW77vNYBmVFH5qv
=nGH1
-----END PGP SIGNATURE-----


Re: Re: [pgsql-ru-general] Re: [pgsql-ru-general] порядок вставки

From
"Dmitry E. Oboukhov"
Date:
> в доке по INSERT про порядок ничего нет, но с какой стати он будет отличаться
> от результатов селекта?


а SELECT * FROM "with_results" может отличаться в порядке?

WITH "bla" AS (
    SELECT
        ..

),
"ble" AS (
    SELECT
        ..
    "bla" -- тут используется "bla" и JOIN с "bla"
)
INSERT
    ..
SELECT * FROM "bla"

и вот соответственно вопрос: может ли секция "ble" изменить порядок
выдачи последующего SELECT из секции "bla"?


если точно задачу сформулировать то получается
вкратце, пишем простой биллинг-лог

на входе приходит txnname и сумма sum

далее табличка с логом (играем на PRIMARY KEY):

id       SERIAL
rollback BOOLEAN NOT NULL DEFAULT FALSE
sum      NUMERIC(11,2)
txnname  TEXT

прочие TIMESTAMP опускаем для краткости


входим в билинг с двумя параметрами (обобщая)
txnname - имя чего-то с чем связана транзакция
sum - сумма

билинг формирует в обычном случае такой INSERT

INSERT TO "billing_log"
  ("rollback", "sum", "txnname")
VALUES
    (FALSE, 10, 'заказ 342')


а в случае, если по данному объекту уже была запись,
то выбирает последнюю, откатывает ее и записывает новую:

INSERT TO "billing_log"
  ("rollback", "sum", "txnname")
VALUES
    (TRUE, -123, 'заказ 342'),
    (FALSE, 10, 'заказ 342')


Соответственно я хочу сформировать секцию WITH, которая формирует эти
(одну или две) записи, чтобы получить атомарный SQL, но возник вот
этот вопрос: сохранится ли порядок записей INSERT SELECT


--

. ''`.                               Dmitry E. Oboukhov
: :’  :   email: unera@debian.org jabber://UNera@uvw.ru
`. `~’              GPGKey: 1024D / F8E26537 2006-11-21
  `- 1B23 D4F8 8EC0 D902 0555  E438 AB8C 00CF F8E2 6537

Attachment
>> в таблицу записываем произошедшие одно за другим события.
>> SERIAL в первичном ключе таким образом определяет какое событие было
>> раньше какое позже (таймстемп тоже есть, но он больше декоративный)
>> поэтому порядок INSERT'ов мне важен.
> Вы поступаете неправильно, и вот почему - во-первых, такие вставки могут идти параллельно, и тогда порядок становится
совсемуж странным; во-вторых, порядок вставки при insert действительно не определен (при каком-то другом объеме данных
иположении звезд сервер может изменить план и порядок будет совсем иным); и то, что оно иногда (а то и практически
всегда)может работать так, как вам надо - не более чем совпадение. Я бы набрался наглости и посоветовал бы либо сделать
timestampне декоративным, либо ввести какой-то свое значение для упорядочивания). 

про параллельные вставки я все понимаю.

те что идут параллельно - они (так устроена система) не предъявляют
требований к тому что одна может записаться раньше другой

основной поток делает один INSERT и все

но вот есть конкретно случаи, когда требуется сохранить
последовательность и соответственно там требуется атомарно записать
две записи в БД.

я в соседнем письме описал задачу более подробно
--

. ''`.                               Dmitry E. Oboukhov
: :’  :   email: unera@debian.org jabber://UNera@uvw.ru
`. `~’              GPGKey: 1024D / F8E26537 2006-11-21
  `- 1B23 D4F8 8EC0 D902 0555  E438 AB8C 00CF F8E2 6537

Attachment
а SELECT * FROM "with_results" может отличаться в порядке?

Надо бы смотреть доку по WITH.
Можно подстраховаться,

with a ( select 1 n, ...),
       b ( select 2 n, ...),
       c ( ... union all ...)
insert into t(z, x) select z, x from c order by n

Я по другому понял вопрос, может ли в запросе insert .. select записи вставиться не в том порядке, в котором их возвращает select. Насколько я понял, нет, потому что для инсерта не создается какого то особого плана, план создается для селекта, просто вместо отправки клиенту записи пишутся в таблицу.

что то я не пойму насчет WITH, зачем он? если формируешь сам, чем не устраивает
INSERT TO "billing_log"
  ("rollback", "sum", "txnname")
VALUES
    (TRUE, -123, 'заказ 342'),
    (FALSE, 10, 'заказ 342')




20 октября 2015 г., 12:39 пользователь Dmitry E. Oboukhov <unera@debian.org> написал:

>> в таблицу записываем произошедшие одно за другим события.
>> SERIAL в первичном ключе таким образом определяет какое событие было
>> раньше какое позже (таймстемп тоже есть, но он больше декоративный)
>> поэтому порядок INSERT'ов мне важен.
> Вы поступаете неправильно, и вот почему - во-первых, такие вставки могут идти параллельно, и тогда порядок становится совсем уж странным; во-вторых, порядок вставки при insert действительно не определен (при каком-то другом объеме данных и положении звезд сервер может изменить план и порядок будет совсем иным); и то, что оно иногда (а то и практически всегда) может работать так, как вам надо - не более чем совпадение. Я бы набрался наглости и посоветовал бы либо сделать timestamp не декоративным, либо ввести какой-то свое значение для упорядочивания).

про параллельные вставки я все понимаю.

те что идут параллельно - они (так устроена система) не предъявляют
требований к тому что одна может записаться раньше другой

основной поток делает один INSERT и все

но вот есть конкретно случаи, когда требуется сохранить
последовательность и соответственно там требуется атомарно записать
две записи в БД.

я в соседнем письме описал задачу более подробно
--

. ''`.                               Dmitry E. Oboukhov
: :’  :   email: unera@debian.org jabber://UNera@uvw.ru
`. `~’              GPGKey: 1024D / F8E26537 2006-11-21
  `- 1B23 D4F8 8EC0 D902 0555  E438 AB8C 00CF F8E2 6537

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)

iEYEAREDAAYFAlYmC9IACgkQq4wAz/jiZTe1ugCgxCvt2YvBgyXAjbB0CFoLNNa7
wyUAn2weG+s6/AzeDJxDSZvhCG+aEy9O
=QRLu
-----END PGP SIGNATURE-----


> Я по другому понял вопрос, может ли в запросе insert .. select записи
> вставиться не в том порядке, в котором их возвращает select. Насколько я понял,
> нет, потому что для инсерта не создается какого то особого плана, план
> создается для селекта, просто вместо отправки клиенту записи пишутся в таблицу.

Да вопрос именно в этом.
интересно: может ли выборка секции WITH быть пересортирована в
процессе выполнения другого подзапроса WITH

WITH "a" AS (
  SELECT ..
),
"b" AS (
  SELECT
   ...
    "a"
)
INSERT INTO ... SELECT * FROM "a";

это первый непонятный кейз

и второй

может ли выборка секции WITH быть пересортирована в процессе
хранения/просто выборки из нее:

SELECT * FROM "a"

строит же план? или всегда выберет из виртуальной таблицы в том
порядке в котором выбралось?

то есть в общем-то хочется понимания о том как устроено хранилище
промежуточных результатов WITH: что там, plain массив или может быть
например hash?


> что то я не пойму насчет WITH, зачем он? если формируешь сам, чем не устраивает
> INSERT TO "billing_log"
> ("rollback", "sum", "txnname")
> VALUES
> (TRUE, -123, 'заказ 342'),
> (FALSE, 10, 'заказ 342')

ну тут я развернул для ясности что я хочу получить, но на практике оба
значения - выборки with

--

. ''`.                               Dmitry E. Oboukhov
: :’  :   email: unera@debian.org jabber://UNera@uvw.ru
`. `~’              GPGKey: 1024D / F8E26537 2006-11-21
  `- 1B23 D4F8 8EC0 D902 0555  E438 AB8C 00CF F8E2 6537

Attachment
что касается второго, видимо, может. это ж обычный запрос, подчиняется общим правилам планировщика.. with, по сути, более удобная форма записи подзапросов, так что order by в итоговом селект не помешает, кажись. хотя в твоем случае на практике скорей всего все будет работать правильно и без order by.

насчет первого, опять не уверен, что понял правильно. именно вот так:

WITH "a" AS (
  SELECT ..
),
"b" AS (
  SELECT
   ...
    "a"
)
INSERT INTO ... SELECT * FROM "a";

???

если да, то не повлияет. а это уже сформированный набор строк, типа временной таблицы или подзапроса,  на нее не повлияет выборка из нее. b AS ( ) просто для примера? а то как то бессмысленно выглядит)


ну и еще раз, на всякий, в любом случае

INSERT INTO dest SELECT * FROM source;  - не важно, откуда возвращает данные SELECT, в dest они будут вставляться в том же порядке, в каком их возвращает SELECT


20 октября 2015 г., 15:45 пользователь Dmitry E. Oboukhov <unera@debian.org> написал:
> Я по другому понял вопрос, может ли в запросе insert .. select записи
> вставиться не в том порядке, в котором их возвращает select. Насколько я понял,
> нет, потому что для инсерта не создается какого то особого плана, план
> создается для селекта, просто вместо отправки клиенту записи пишутся в таблицу.

Да вопрос именно в этом.
интересно: может ли выборка секции WITH быть пересортирована в
процессе выполнения другого подзапроса WITH

WITH "a" AS (
  SELECT ..
),
"b" AS (
  SELECT
   ...
    "a"
)
INSERT INTO ... SELECT * FROM "a";

это первый непонятный кейз

и второй

может ли выборка секции WITH быть пересортирована в процессе
хранения/просто выборки из нее:

SELECT * FROM "a"

строит же план? или всегда выберет из виртуальной таблицы в том
порядке в котором выбралось?

то есть в общем-то хочется понимания о том как устроено хранилище
промежуточных результатов WITH: что там, plain массив или может быть
например hash?


> что то я не пойму насчет WITH, зачем он? если формируешь сам, чем не устраивает
> INSERT TO "billing_log"
> ("rollback", "sum", "txnname")
> VALUES
> (TRUE, -123, 'заказ 342'),
> (FALSE, 10, 'заказ 342')

ну тут я развернул для ясности что я хочу получить, но на практике оба
значения - выборки with

--

. ''`.                               Dmitry E. Oboukhov
: :’  :   email: unera@debian.org jabber://UNera@uvw.ru
`. `~’              GPGKey: 1024D / F8E26537 2006-11-21
  `- 1B23 D4F8 8EC0 D902 0555  E438 AB8C 00CF F8E2 6537

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)

iEUEAREDAAYFAlYmN4QACgkQq4wAz/jiZTcrOwCYk+hBbI9zRBvJXRolXvTJ6n4q
/wCgmPf7oZOHDoHRJpfHQGjrv0SUNpg=
=GkFE
-----END PGP SIGNATURE-----