PostgreSQLдин ички механизмдеринин өзгөчөлүктөрү анын кээ бир кырдаалдарда өтө тез, ал эми башкаларында "өтө ылдам эмес" болушуна мүмкүндүк берет. Бүгүн биз DBMS кантип иштээри менен иштеп чыгуучунун аны менен кылган ишинин ортосундагы чыр-чатактын классикалык мисалына токтолобуз - UPDATE vs MVCC принциптери.
Кыскача окуядан
Качан катар UPDATE буйругу менен өзгөртүлгөндө, чындыгында эки операция аткарылат: DELETE жана INSERT. IN саптын учурдагы версиясы xmax UPDATE аткарган транзакциянын санына барабар коюлган. Андан кийин ал түзүлөт жаңы версия ошол эле сызык; анын xmin мааниси мурунку версиянын xmax маанисине дал келет.
Бул бүтүм аяктагандан кийин бир нече убакыт өткөндөн кийин, жараша эски же жаңы версия COMMIT/ROOLBACK
, таанылат "өлүк" (өлүк кортеждер) өтүп жатканда VACUUM
столго ылайык жана тазаланган.
Бирок бул дароо болбойт, бирок "өлүү" менен көйгөйлөр абдан тез эле пайда болот - кайталап же
№1: Мен аны жылдырууну жакшы көрөм
Сиздин методуңуз бизнес логикасында иштеп жатат дейли, күтүлбөгөн жерден ал кандайдыр бир жазууда X талаасын жаңыртуу керектигин түшүнөт:
UPDATE tbl SET X = <newX> WHERE pk = $1;
Андан кийин, аткарылган сайын, Y талаасы да жаңыртылышы керек экен:
UPDATE tbl SET Y = <newY> WHERE pk = $1;
... анан дагы Z - эмнеге майда-чүйдө нерселерге убакыт коротот?
UPDATE tbl SET Z = <newZ> WHERE pk = $1;
Азыр базада бул жазуунун канча версиясы бар? Ооба, 4 даана! Алардын бири тиешелүү, ал эми үчөөнү сизден кийин [auto]VACUUM аркылуу тазалашыңыз керек.
Мындай кылба! Колдонуу бир суроодо бардык талааларды жаңыртуу — дээрлик ар дайым методдун логикасын төмөнкүдөй өзгөртүүгө болот:
UPDATE tbl SET X = <newX>, Y = <newY>, Z = <newZ> WHERE pk = $1;
№2: Колдонуу МЕНЕН ДИРЕКТОР, Лука!
Демек, сен дагы эле каалаган
UPDATE tbl SET X = <newX> WHERE pk BETWEEN $1 AND $2;
Болжол менен бул формадагы суроо-талап көп учурда жана дээрлик дайыма бош жаңы талааны толтуруу үчүн эмес, маалыматтардагы кээ бир каталарды оңдоо үчүн болот. Ошол эле учурда, ал өзү бар болгон маалыматтардын тууралыгы такыр эске алынбайт - бирок бекер! Башкача айтканда, жазуу талап кылынган нерсени камтыса дагы, кайра жазылат - бирок эмне үчүн? Аны оңдойлу:
UPDATE tbl SET X = <newX> WHERE pk BETWEEN $1 AND $2 AND X IS DISTINCT FROM <newX>;
Көптөгөн адамдар мындай сонун оператордун бар экенин билишпейт, ошондуктан бул жерде алдамчылык баракча IS DISTINCT FROM
жана башка логикалык операторлор жардам берет:
... жана комплекстеги операциялар жөнүндө бир аз ROW()
- туюнтмалар:
#3: Мен сүйүктүүмдү... бөгөт коюу менен тааныйм
ишке киргизилип жатышат эки бирдей параллелдүү процесс, алардын ар бири жазууну "иштеп жатат" деп белгилөөгө аракет кылат:
UPDATE tbl SET processing = TRUE WHERE pk = $1;
Бул процесстер чындыгында бири-биринен көз карандысыз иштерди жасаса да, бирок ошол эле ID ичинде экинчи кардар биринчи транзакция аяктаганга чейин бул өтүнүч боюнча "кулпуланып" калат.
Чечим №1: тапшырма мурдагыга кыскарды
Келгиле, аны кайра кошуп коёлу IS DISTINCT FROM
:
UPDATE tbl SET processing = TRUE WHERE pk = $1 AND processing IS DISTINCT FROM TRUE;
Бул формада экинчи суроо-талап базада эч нерсени өзгөртпөйт, баары мурунтан эле болушу керек - ошондуктан бөгөт коюу болбойт. Андан кийин, биз колдонулган алгоритмде жазууну "таббоо" фактысын иштетебиз.
Чечим №2: кеңеш кулпулары
Сиз жөнүндө окуй турган өзүнчө макала үчүн чоң тема
Чечим №3: акылсыз чалуулар
Бирок бул так сиз менен болушу керек бир эле жазуу менен бир убакта иштөө? Же, мисалы, кардар тарабында бизнес логикасын чакыруу алгоритмдери менен баш аламандык кылдыңызбы? Анан ойлонуп көрсөң?..
Source: www.habr.com