Estou curioso para saber como esta declaração atualizou 3 linhas no Postgres. Todas as outras vezes que executei, ele atualizaria 0 ou 1. Existe uma maneira de descobrir quais linhas?
bestsales=# update keyword set revenue = random()*10 where id = cast(random()*99999 as int);
UPDATE 3
id
é a chave primária.
id | integer | not null default nextval('keyword_id_seq'::regclass)
"keyword_pkey" PRIMARY KEY, btree (id)
Eu tentei executá-lo como SELECT
:
bestsales=# select * from keyword where id = cast(random()*99999 as int);
id | keyword | seed_id | source | search_count | country | language | volume | cpc | competition | modified_on | google_violation | revenue | bing_violation
-------+---------------------+---------+--------+--------------+---------+----------+--------+------+-------------+-------------+------------------+---------+----------------
6833 | vizio m190mv | | GOOGLE | 0 | | | 70 | 0.38 | 0.90 | | | |
65765 | shiatsu massage mat | | SPYFU | 0 | | | 110 | 0.69 | | | | |
87998 | granary flour | | SPYFU | 0 | | | 40 | 0.04 | | | | |
(3 rows)
E às vezes retornava mais de um. Como isso é possível?
PostgreSQL 9.5.3
Parece que
random()
é executado uma vez por linha e não uma vez por toda a instrução. Portanto, cadaid
valor é verificado em relação a um valor aleatório diferente. Você pode obter 0, 1, 2 ou mais, até mesmo todas as linhas da tabela, embora essa possibilidade seja muito pequena mesmo com 10 linhas.Se você deseja que seja executado uma vez e assim obter apenas um valor e atualizar apenas zero ou uma linha, você pode usar um CTE, que é conhecido por ser avaliado antes da consulta principal:
e o mesmo para
UPDATE
:Mesmo uma subconsulta simples faz o trabalho:
A subconsulta é avaliada uma vez e apenas uma linha é atualizada (se o
id
valor existir). Um pouco mais barato do que usar um CTE.Se você usar a expressão sem wrapper de subconsulta,
random()
é avaliada para cada linha, porque é uma função volátil . Isso ocorre por design e geralmente é o comportamento desejado.Quanto à sua pergunta adicional:
Não com segurança garantida, mas se você executar esta consulta imediatamente após o
UPDATE
, as linhas que compartilham o ID de transação mais alto emxmin
valor são as atualizadas ou inseridas mais recentemente.Todas as linhas inseridas/atualizadas na mesma transação compartilham o mesmo ID da transação. Se você tiver várias
INSERT
/UPDATE
operações na mesma tabela em uma transação, precisará examinar o ID do comandocmin
adicionalmente:Não há garantias porque
xmin
está sujeito a possível recuperação do ID da transação. Mas normalmente funciona.xmin
ecmin
são colunas do sistema no cabeçalho da linha.O manual sobre tipos de identificador de objeto.
Ainda na mesma transação (atualização ainda não confirmada), existe um método ainda mais seguro:
Como visualizar as tuplas alteradas em uma transação do PostgreSQL?
Como comparar xmin e txid_current () após o wraparound do ID das transações?
Relacionado: