Antipatróns de PostgreSQL: loitando contra hordas de "mortos"

As peculiaridades dos mecanismos internos de PostgreSQL permiten que sexa moi rápido nalgunhas situacións e "non moi rápido" noutras. Hoxe centrarémonos nun exemplo clásico dun conflito entre como funciona un DBMS e o que fai o desenvolvedor con el: ACTUALIZACIÓN vs principios MVCC.

Breve historia de gran artigo:

Cando se modifica unha fila mediante un comando UPDATE, realízanse dúas operacións: DELETE e INSERT. EN versión actual da cadea xmax establécese igual ao número da transacción que realizou a ACTUALIZACIÓN. Despois créase unha nova versión a mesma liña; o seu valor xmin coincide co valor xmax da versión anterior.

Algún tempo despois de que se complete esta transacción, a versión antiga ou nova, dependendo de COMMIT/ROOLBACK, será recoñecido "morto" (tuplas mortas) ao pasar VACUUM segundo a táboa e despexado.

Antipatróns de PostgreSQL: loitando contra hordas de "mortos"

Pero isto non ocorrerá de inmediato, pero os problemas cos "mortos" pódense adquirir moi rapidamente - con repetidas ou actualización masiva de rexistros nunha mesa grande, e un pouco máis tarde atoparás a mesma situación VACUUM non poderá axudar.

#1: Gústame movelo

Digamos que o teu método está a traballar na lóxica empresarial e, de súpeto, dáse conta de que sería necesario actualizar o campo X nalgún rexistro:

UPDATE tbl SET X = <newX> WHERE pk = $1;

Entón, a medida que avanza a execución, resulta que o campo Y tamén debe actualizarse:

UPDATE tbl SET Y = <newY> WHERE pk = $1;

... e despois tamén Z - por que perder o tempo en bagatelas?

UPDATE tbl SET Z = <newZ> WHERE pk = $1;

Cantas versións deste rexistro temos agora na base de datos? Si, 4 pezas! Deles, un é relevante e 3 terás que limpar despois de ti mediante [auto]VACUUM.

Non o fagas deste xeito! Use actualizando todos os campos nunha única solicitude - case sempre a lóxica do método pódese cambiar así:

UPDATE tbl SET X = <newX>, Y = <newY>, Z = <newZ> WHERE pk = $1;

#2: O uso é distinto de, Luke!

Entón, aínda querías actualizar moitos, moitos rexistros nunha táboa (durante o uso dun script ou conversor, por exemplo). E algo como isto entra no guión:

UPDATE tbl SET X = <newX> WHERE pk BETWEEN $1 AND $2;

Unha solicitude de aproximadamente este formulario ocorre con bastante frecuencia e case sempre non para cubrir un novo campo baleiro, senón para corrixir algúns erros nos datos. Ao mesmo tempo, ela mesma non se ten en conta en absoluto a corrección dos datos existentes - pero en balde! É dicir, o rexistro está reescrito, aínda que contiña exactamente o que se quería, pero por que? Imos corrixilo:

UPDATE tbl SET X = <newX> WHERE pk BETWEEN $1 AND $2 AND X IS DISTINCT FROM <newX>;

Moitas persoas non son conscientes da existencia dun operador tan marabilloso, así que aquí tes unha folla de trucos IS DISTINCT FROM e outros operadores lóxicos para axudar:
Antipatróns de PostgreSQL: loitando contra hordas de "mortos"
... e un pouco sobre operacións en complexo ROW()-expresións:
Antipatróns de PostgreSQL: loitando contra hordas de "mortos"

# 3: Recoñezo á miña querida por... bloqueo

están sendo postos en marcha dous procesos paralelos idénticos, cada un dos cales tenta marcar a entrada que está "en curso":

UPDATE tbl SET processing = TRUE WHERE pk = $1;

Aínda que estes procesos realmente fagan cousas independentes entre si, pero dentro do mesmo ID, o segundo cliente estará "bloqueado" nesta solicitude ata que se complete a primeira transacción.

Solución # 1: a tarefa redúcese á anterior

Engadímolo de novo IS DISTINCT FROM:

UPDATE tbl SET processing = TRUE WHERE pk = $1 AND processing IS DISTINCT FROM TRUE;

Neste formulario, a segunda solicitude simplemente non cambiará nada na base de datos, xa está todo como debería ser; polo tanto, non se producirá o bloqueo. A continuación, procesamos o feito de "non atopar" o rexistro no algoritmo aplicado.

Solución # 2: peches de asesoramento

Un gran tema para un artigo separado, no que podes ler métodos de aplicación e "rake" de bloqueo recomendado.

Solución # 3: chamadas estúpidas

Pero isto é exactamente o que debería pasarche traballo simultáneo co mesmo rexistro? Ou estropeou os algoritmos para chamar á lóxica empresarial no lado do cliente, por exemplo? E se o pensas?...

Fonte: www.habr.com

Engadir un comentario