MVCC-3. ಸ್ಟ್ರಿಂಗ್ ಆವೃತ್ತಿಗಳು

ಆದ್ದರಿಂದ, ನಾವು ಸಂಬಂಧಿಸಿದ ಸಮಸ್ಯೆಗಳನ್ನು ಪರಿಗಣಿಸಿದ್ದೇವೆ ನಿರೋಧನ, ಮತ್ತು ಬಗ್ಗೆ ಹಿಮ್ಮೆಟ್ಟಿಸಿದರು ಕಡಿಮೆ ಮಟ್ಟದಲ್ಲಿ ಡೇಟಾವನ್ನು ಸಂಘಟಿಸುವುದು. ಮತ್ತು ಅಂತಿಮವಾಗಿ ನಾವು ಅತ್ಯಂತ ಆಸಕ್ತಿದಾಯಕ ಭಾಗವನ್ನು ಪಡೆದುಕೊಂಡಿದ್ದೇವೆ - ಸ್ಟ್ರಿಂಗ್ ಆವೃತ್ತಿಗಳು.

ಶಿರೋಲೇಖ

ನಾವು ಈಗಾಗಲೇ ಹೇಳಿದಂತೆ, ಪ್ರತಿ ಸಾಲು ಏಕಕಾಲದಲ್ಲಿ ಡೇಟಾಬೇಸ್ನಲ್ಲಿ ಹಲವಾರು ಆವೃತ್ತಿಗಳಲ್ಲಿ ಅಸ್ತಿತ್ವದಲ್ಲಿರಬಹುದು. ಒಂದು ಆವೃತ್ತಿಯನ್ನು ಇನ್ನೊಂದರಿಂದ ಹೇಗಾದರೂ ಪ್ರತ್ಯೇಕಿಸಬೇಕು. ಈ ಉದ್ದೇಶಕ್ಕಾಗಿ, ಪ್ರತಿ ಆವೃತ್ತಿಯು ಈ ಆವೃತ್ತಿಯ (xmin ಮತ್ತು xmax) ಕ್ರಿಯೆಯ "ಸಮಯ" ವನ್ನು ನಿರ್ಧರಿಸುವ ಎರಡು ಗುರುತುಗಳನ್ನು ಹೊಂದಿರುತ್ತದೆ. ಉಲ್ಲೇಖಗಳಲ್ಲಿ - ಏಕೆಂದರೆ ಇದು ಬಳಸಲಾಗುವ ಸಮಯವಲ್ಲ, ಆದರೆ ವಿಶೇಷ ಹೆಚ್ಚುತ್ತಿರುವ ಕೌಂಟರ್. ಮತ್ತು ಈ ಕೌಂಟರ್ ವಹಿವಾಟಿನ ಸಂಖ್ಯೆಯಾಗಿದೆ.

(ಎಂದಿನಂತೆ, ವಾಸ್ತವವು ಹೆಚ್ಚು ಜಟಿಲವಾಗಿದೆ: ಕೌಂಟರ್‌ನ ಸೀಮಿತ ಬಿಟ್ ಸಾಮರ್ಥ್ಯದ ಕಾರಣದಿಂದಾಗಿ ವಹಿವಾಟಿನ ಸಂಖ್ಯೆಯು ಸಾರ್ವಕಾಲಿಕವಾಗಿ ಹೆಚ್ಚಾಗುವುದಿಲ್ಲ. ಆದರೆ ನಾವು ಘನೀಕರಣಕ್ಕೆ ಬಂದಾಗ ನಾವು ಈ ವಿವರಗಳನ್ನು ವಿವರವಾಗಿ ನೋಡುತ್ತೇವೆ.)

ಸಾಲನ್ನು ರಚಿಸಿದಾಗ, xmin ಅನ್ನು INSERT ಆಜ್ಞೆಯನ್ನು ನೀಡಿದ ವಹಿವಾಟು ಸಂಖ್ಯೆಗೆ ಹೊಂದಿಸಲಾಗುತ್ತದೆ ಮತ್ತು xmax ಅನ್ನು ಖಾಲಿ ಬಿಡಲಾಗುತ್ತದೆ.

ಸಾಲನ್ನು ಅಳಿಸಿದಾಗ, ಪ್ರಸ್ತುತ ಆವೃತ್ತಿಯ xmax ಮೌಲ್ಯವನ್ನು ಡಿಲೀಟ್ ಮಾಡಿದ ವಹಿವಾಟಿನ ಸಂಖ್ಯೆಯೊಂದಿಗೆ ಗುರುತಿಸಲಾಗುತ್ತದೆ.

UPDATE ಆಜ್ಞೆಯಿಂದ ಸಾಲನ್ನು ಮಾರ್ಪಡಿಸಿದಾಗ, ಎರಡು ಕಾರ್ಯಾಚರಣೆಗಳನ್ನು ವಾಸ್ತವವಾಗಿ ನಿರ್ವಹಿಸಲಾಗುತ್ತದೆ: DELETE ಮತ್ತು INSERT. ಸಾಲಿನ ಪ್ರಸ್ತುತ ಆವೃತ್ತಿಯು ಅಪ್‌ಡೇಟ್ ಮಾಡಿದ ವಹಿವಾಟಿನ ಸಂಖ್ಯೆಗೆ ಸಮಾನವಾದ xmax ಅನ್ನು ಹೊಂದಿಸುತ್ತದೆ. ನಂತರ ಅದೇ ಸ್ಟ್ರಿಂಗ್‌ನ ಹೊಸ ಆವೃತ್ತಿಯನ್ನು ರಚಿಸಲಾಗಿದೆ; ಅದರ xmin ಮೌಲ್ಯವು ಹಿಂದಿನ ಆವೃತ್ತಿಯ xmax ಮೌಲ್ಯದೊಂದಿಗೆ ಹೊಂದಿಕೆಯಾಗುತ್ತದೆ.

xmin ಮತ್ತು xmax ಕ್ಷೇತ್ರಗಳನ್ನು ಸಾಲಿನ ಆವೃತ್ತಿಯ ಹೆಡರ್‌ನಲ್ಲಿ ಸೇರಿಸಲಾಗಿದೆ. ಈ ಕ್ಷೇತ್ರಗಳ ಜೊತೆಗೆ, ಹೆಡರ್ ಇತರವುಗಳನ್ನು ಒಳಗೊಂಡಿದೆ, ಉದಾಹರಣೆಗೆ:

  • infomask ಈ ಆವೃತ್ತಿಯ ಗುಣಲಕ್ಷಣಗಳನ್ನು ವ್ಯಾಖ್ಯಾನಿಸುವ ಬಿಟ್‌ಗಳ ಸರಣಿಯಾಗಿದೆ. ಅವುಗಳಲ್ಲಿ ಸಾಕಷ್ಟು ಇವೆ; ನಾವು ಕ್ರಮೇಣ ಮುಖ್ಯವಾದವುಗಳನ್ನು ಪರಿಗಣಿಸುತ್ತೇವೆ.
  • ctid ಅದೇ ಸಾಲಿನ ಮುಂದಿನ, ಹೊಸ ಆವೃತ್ತಿಗೆ ಲಿಂಕ್ ಆಗಿದೆ. ಸ್ಟ್ರಿಂಗ್‌ನ ಹೊಸ, ಅತ್ಯಂತ ಪ್ರಸ್ತುತ ಆವೃತ್ತಿಗೆ, ctid ಈ ಆವೃತ್ತಿಯನ್ನು ಸೂಚಿಸುತ್ತದೆ. ಸಂಖ್ಯೆಯು ರೂಪವನ್ನು ಹೊಂದಿದೆ (x,y), ಇಲ್ಲಿ x ಎಂಬುದು ಪುಟ ಸಂಖ್ಯೆ, y ಎಂಬುದು ಸರಣಿಯಲ್ಲಿನ ಸೂಚ್ಯಂಕ ಸಂಖ್ಯೆ.
  • ಶೂನ್ಯ ಬಿಟ್‌ಮ್ಯಾಪ್ - ಶೂನ್ಯ ಮೌಲ್ಯವನ್ನು ಹೊಂದಿರುವ ನಿರ್ದಿಷ್ಟ ಆವೃತ್ತಿಯ ಕಾಲಮ್‌ಗಳನ್ನು ಗುರುತಿಸುತ್ತದೆ (NULL). NULL ಸಾಮಾನ್ಯ ಡೇಟಾ ಪ್ರಕಾರದ ಮೌಲ್ಯಗಳಲ್ಲಿ ಒಂದಲ್ಲ, ಆದ್ದರಿಂದ ಗುಣಲಕ್ಷಣವನ್ನು ಪ್ರತ್ಯೇಕವಾಗಿ ಸಂಗ್ರಹಿಸಬೇಕು.

ಪರಿಣಾಮವಾಗಿ, ಹೆಡರ್ ಸಾಕಷ್ಟು ದೊಡ್ಡದಾಗಿದೆ - ಸಾಲಿನ ಪ್ರತಿ ಆವೃತ್ತಿಗೆ ಕನಿಷ್ಠ 23 ಬೈಟ್‌ಗಳು, ಮತ್ತು ಸಾಮಾನ್ಯವಾಗಿ NULL ಬಿಟ್‌ಮ್ಯಾಪ್‌ನಿಂದಾಗಿ ಹೆಚ್ಚು. ಟೇಬಲ್ "ಕಿರಿದಾದ" (ಅಂದರೆ, ಕೆಲವು ಕಾಲಮ್ಗಳನ್ನು ಒಳಗೊಂಡಿದ್ದರೆ), ಓವರ್ಹೆಡ್ ಉಪಯುಕ್ತ ಮಾಹಿತಿಗಿಂತ ಹೆಚ್ಚಿನದನ್ನು ತೆಗೆದುಕೊಳ್ಳಬಹುದು.

ಸೇರಿಸಲು

ಅಳವಡಿಕೆಯಿಂದ ಪ್ರಾರಂಭಿಸಿ ಕೆಳಮಟ್ಟದ ಸ್ಟ್ರಿಂಗ್ ಕಾರ್ಯಾಚರಣೆಗಳನ್ನು ಹೇಗೆ ನಿರ್ವಹಿಸಲಾಗುತ್ತದೆ ಎಂಬುದನ್ನು ಹತ್ತಿರದಿಂದ ನೋಡೋಣ.

ಪ್ರಯೋಗಗಳಿಗಾಗಿ, ಎರಡು ಕಾಲಮ್‌ಗಳು ಮತ್ತು ಅವುಗಳಲ್ಲಿ ಒಂದು ಸೂಚ್ಯಂಕದೊಂದಿಗೆ ಹೊಸ ಕೋಷ್ಟಕವನ್ನು ರಚಿಸೋಣ:

=> CREATE TABLE t(
  id serial,
  s text
);
=> CREATE INDEX ON t(s);

ವಹಿವಾಟು ಪ್ರಾರಂಭಿಸಿದ ನಂತರ ಒಂದು ಸಾಲನ್ನು ಸೇರಿಸೋಣ.

=> BEGIN;
=> INSERT INTO t(s) VALUES ('FOO');

ನಮ್ಮ ಪ್ರಸ್ತುತ ವಹಿವಾಟು ಸಂಖ್ಯೆ ಇಲ್ಲಿದೆ:

=> SELECT txid_current();
 txid_current 
--------------
         3664
(1 row)

ಪುಟದ ವಿಷಯಗಳನ್ನು ನೋಡೋಣ. ಪುಟಪರಿಶೀಲನೆ ವಿಸ್ತರಣೆಯ heap_page_items ಕಾರ್ಯವು ಪಾಯಿಂಟರ್‌ಗಳು ಮತ್ತು ಸಾಲು ಆವೃತ್ತಿಗಳ ಕುರಿತು ಮಾಹಿತಿಯನ್ನು ಪಡೆಯಲು ನಿಮಗೆ ಅನುಮತಿಸುತ್ತದೆ:

=> SELECT * FROM heap_page_items(get_raw_page('t',0)) gx
-[ RECORD 1 ]-------------------
lp          | 1
lp_off      | 8160
lp_flags    | 1
lp_len      | 32
t_xmin      | 3664
t_xmax      | 0
t_field3    | 0
t_ctid      | (0,1)
t_infomask2 | 2
t_infomask  | 2050
t_hoff      | 24
t_bits      | 
t_oid       | 
t_data      | x0100000009464f4f

PostgreSQL ನಲ್ಲಿ ಹೀಪ್ ಎಂಬ ಪದವು ಕೋಷ್ಟಕಗಳನ್ನು ಸೂಚಿಸುತ್ತದೆ ಎಂಬುದನ್ನು ಗಮನಿಸಿ. ಇದು ಪದದ ಮತ್ತೊಂದು ವಿಚಿತ್ರ ಬಳಕೆಯಾಗಿದೆ - ಒಂದು ರಾಶಿ ತಿಳಿದಿದೆ ಡೇಟಾ ರಚನೆ, ಇದು ಟೇಬಲ್‌ನೊಂದಿಗೆ ಯಾವುದೇ ಸಾಮಾನ್ಯತೆಯನ್ನು ಹೊಂದಿಲ್ಲ. ಇಲ್ಲಿ ಪದವನ್ನು ಆದೇಶದ ಸೂಚಿಕೆಗಳಿಗೆ ವಿರುದ್ಧವಾಗಿ "ಎಲ್ಲವನ್ನೂ ಒಟ್ಟಿಗೆ ಎಸೆಯಲಾಗುತ್ತದೆ" ಎಂಬ ಅರ್ಥದಲ್ಲಿ ಬಳಸಲಾಗುತ್ತದೆ.

ಕಾರ್ಯವು "ಇರುವಂತೆ" ಡೇಟಾವನ್ನು ತೋರಿಸುತ್ತದೆ, ಅದನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳಲು ಕಷ್ಟವಾಗುತ್ತದೆ. ಅದನ್ನು ಲೆಕ್ಕಾಚಾರ ಮಾಡಲು, ನಾವು ಮಾಹಿತಿಯ ಭಾಗವನ್ನು ಮಾತ್ರ ಬಿಡುತ್ತೇವೆ ಮತ್ತು ಅದನ್ನು ಅರ್ಥೈಸಿಕೊಳ್ಳುತ್ತೇವೆ:

=> SELECT '(0,'||lp||')' AS ctid,
       CASE lp_flags
         WHEN 0 THEN 'unused'
         WHEN 1 THEN 'normal'
         WHEN 2 THEN 'redirect to '||lp_off
         WHEN 3 THEN 'dead'
       END AS state,
       t_xmin as xmin,
       t_xmax as xmax,
       (t_infomask & 256) > 0  AS xmin_commited,
       (t_infomask & 512) > 0  AS xmin_aborted,
       (t_infomask & 1024) > 0 AS xmax_commited,
       (t_infomask & 2048) > 0 AS xmax_aborted,
       t_ctid
FROM heap_page_items(get_raw_page('t',0)) gx
-[ RECORD 1 ]-+-------
ctid          | (0,1)
state         | normal
xmin          | 3664
xmax          | 0
xmin_commited | f
xmin_aborted  | f
xmax_commited | f
xmax_aborted  | t
t_ctid        | (0,1)

ನಾವು ಮಾಡಿದ್ದು ಇಲ್ಲಿದೆ:

  • t_ctid: (ಪುಟ ಸಂಖ್ಯೆ, ಸೂಚ್ಯಂಕ ಸಂಖ್ಯೆ) ನಂತೆ ಕಾಣುವಂತೆ ಮಾಡಲು ಸೂಚ್ಯಂಕ ಸಂಖ್ಯೆಗೆ ಶೂನ್ಯವನ್ನು ಸೇರಿಸಲಾಗಿದೆ.
  • lp_flags ಪಾಯಿಂಟರ್‌ನ ಸ್ಥಿತಿಯನ್ನು ಅರ್ಥೈಸಲಾಗಿದೆ. ಇಲ್ಲಿ ಅದು "ಸಾಮಾನ್ಯ" - ಇದರರ್ಥ ಪಾಯಿಂಟರ್ ವಾಸ್ತವವಾಗಿ ಸ್ಟ್ರಿಂಗ್ನ ಆವೃತ್ತಿಯನ್ನು ಸೂಚಿಸುತ್ತದೆ. ನಾವು ನಂತರ ಇತರ ಅರ್ಥಗಳನ್ನು ನೋಡೋಣ.
  • ಎಲ್ಲಾ ಮಾಹಿತಿ ಬಿಟ್‌ಗಳಲ್ಲಿ, ಇಲ್ಲಿಯವರೆಗೆ ಕೇವಲ ಎರಡು ಜೋಡಿಗಳನ್ನು ಮಾತ್ರ ಗುರುತಿಸಲಾಗಿದೆ. xmin_committed ಮತ್ತು xmin_aborted ಬಿಟ್‌ಗಳು ವಹಿವಾಟು ಸಂಖ್ಯೆ xmin ಬದ್ಧವಾಗಿದೆಯೇ ಎಂಬುದನ್ನು ಸೂಚಿಸುತ್ತದೆ (ನಿರತಗೊಂಡಿದೆ). ಎರಡು ರೀತಿಯ ಬಿಟ್‌ಗಳು ವಹಿವಾಟು ಸಂಖ್ಯೆ xmax ಅನ್ನು ಉಲ್ಲೇಖಿಸುತ್ತವೆ.

ನಾವು ಏನು ನೋಡುತ್ತೇವೆ? ನೀವು ಸಾಲನ್ನು ಸೇರಿಸಿದಾಗ, ಕೋಷ್ಟಕ ಪುಟದಲ್ಲಿ ಸೂಚ್ಯಂಕ ಸಂಖ್ಯೆ 1 ಕಾಣಿಸಿಕೊಳ್ಳುತ್ತದೆ, ಇದು ಸಾಲಿನ ಮೊದಲ ಮತ್ತು ಏಕೈಕ ಆವೃತ್ತಿಯನ್ನು ಸೂಚಿಸುತ್ತದೆ.

ಸ್ಟ್ರಿಂಗ್ ಆವೃತ್ತಿಯಲ್ಲಿ, xmin ಕ್ಷೇತ್ರವು ಪ್ರಸ್ತುತ ವಹಿವಾಟು ಸಂಖ್ಯೆಯಿಂದ ತುಂಬಿದೆ. ವಹಿವಾಟು ಇನ್ನೂ ಸಕ್ರಿಯವಾಗಿದೆ, ಆದ್ದರಿಂದ xmin_committed ಮತ್ತು xmin_aborted ಬಿಟ್‌ಗಳನ್ನು ಹೊಂದಿಸಲಾಗಿಲ್ಲ.

ಸಾಲಿನ ಆವೃತ್ತಿ ctid ಕ್ಷೇತ್ರವು ಅದೇ ಸಾಲನ್ನು ಸೂಚಿಸುತ್ತದೆ. ಇದರರ್ಥ ಹೊಸ ಆವೃತ್ತಿಯು ಅಸ್ತಿತ್ವದಲ್ಲಿಲ್ಲ.

Xmax ಕ್ಷೇತ್ರವು ನಕಲಿ ಸಂಖ್ಯೆ 0 ನೊಂದಿಗೆ ತುಂಬಿದೆ ಏಕೆಂದರೆ ಸಾಲಿನ ಈ ಆವೃತ್ತಿಯನ್ನು ಅಳಿಸಲಾಗಿಲ್ಲ ಮತ್ತು ಪ್ರಸ್ತುತವಾಗಿದೆ. xmax_aborted ಬಿಟ್ ಅನ್ನು ಹೊಂದಿಸಿರುವ ಕಾರಣ ವಹಿವಾಟುಗಳು ಈ ಸಂಖ್ಯೆಗೆ ಗಮನ ಕೊಡುವುದಿಲ್ಲ.

ವಹಿವಾಟು ಸಂಖ್ಯೆಗಳಿಗೆ ಮಾಹಿತಿ ಬಿಟ್‌ಗಳನ್ನು ಸೇರಿಸುವ ಮೂಲಕ ಓದುವಿಕೆಯನ್ನು ಸುಧಾರಿಸುವತ್ತ ಇನ್ನೂ ಒಂದು ಹೆಜ್ಜೆ ಇಡೋಣ. ಮತ್ತು ನಾವು ಕಾರ್ಯವನ್ನು ರಚಿಸೋಣ, ಏಕೆಂದರೆ ನಮಗೆ ಒಂದಕ್ಕಿಂತ ಹೆಚ್ಚು ಬಾರಿ ವಿನಂತಿಯ ಅಗತ್ಯವಿರುತ್ತದೆ:

=> CREATE FUNCTION heap_page(relname text, pageno integer)
RETURNS TABLE(ctid tid, state text, xmin text, xmax text, t_ctid tid)
AS $$
SELECT (pageno,lp)::text::tid AS ctid,
       CASE lp_flags
         WHEN 0 THEN 'unused'
         WHEN 1 THEN 'normal'
         WHEN 2 THEN 'redirect to '||lp_off
         WHEN 3 THEN 'dead'
       END AS state,
       t_xmin || CASE
         WHEN (t_infomask & 256) > 0 THEN ' (c)'
         WHEN (t_infomask & 512) > 0 THEN ' (a)'
         ELSE ''
       END AS xmin,
       t_xmax || CASE
         WHEN (t_infomask & 1024) > 0 THEN ' (c)'
         WHEN (t_infomask & 2048) > 0 THEN ' (a)'
         ELSE ''
       END AS xmax,
       t_ctid
FROM heap_page_items(get_raw_page(relname,pageno))
ORDER BY lp;
$$ LANGUAGE SQL;

ಈ ರೂಪದಲ್ಲಿ, ಸಾಲಿನ ಆವೃತ್ತಿಯ ಹೆಡರ್‌ನಲ್ಲಿ ಏನು ನಡೆಯುತ್ತಿದೆ ಎಂಬುದು ಹೆಚ್ಚು ಸ್ಪಷ್ಟವಾಗಿದೆ:

=> SELECT * FROM heap_page('t',0);
 ctid  | state  | xmin | xmax  | t_ctid 
-------+--------+------+-------+--------
 (0,1) | normal | 3664 | 0 (a) | (0,1)
(1 row)

xmin ಮತ್ತು xmax ಎಂಬ ಹುಸಿ ಕಾಲಮ್‌ಗಳನ್ನು ಬಳಸಿಕೊಂಡು ಒಂದೇ ರೀತಿಯ, ಆದರೆ ಗಮನಾರ್ಹವಾಗಿ ಕಡಿಮೆ ವಿವರವಾದ ಮಾಹಿತಿಯನ್ನು ಟೇಬಲ್‌ನಿಂದಲೇ ಪಡೆಯಬಹುದು:

=> SELECT xmin, xmax, * FROM t;
 xmin | xmax | id |  s  
------+------+----+-----
 3664 |    0 |  1 | FOO
(1 row)

ಸ್ಥಿರೀಕರಣ

ವಹಿವಾಟು ಯಶಸ್ವಿಯಾಗಿ ಪೂರ್ಣಗೊಂಡರೆ, ನೀವು ಅದರ ಸ್ಥಿತಿಯನ್ನು ನೆನಪಿಟ್ಟುಕೊಳ್ಳಬೇಕು - ಅದು ಬದ್ಧವಾಗಿದೆ ಎಂಬುದನ್ನು ಗಮನಿಸಿ. ಇದನ್ನು ಮಾಡಲು, XACT ಎಂಬ ರಚನೆಯನ್ನು ಬಳಸಲಾಗುತ್ತದೆ (ಮತ್ತು ಆವೃತ್ತಿ 10 ಕ್ಕಿಂತ ಮೊದಲು ಇದನ್ನು CLOG (ಕಮಿಟ್ ಲಾಗ್) ಎಂದು ಕರೆಯಲಾಗುತ್ತಿತ್ತು ಮತ್ತು ಈ ಹೆಸರನ್ನು ಇನ್ನೂ ವಿವಿಧ ಸ್ಥಳಗಳಲ್ಲಿ ಕಾಣಬಹುದು).

XACT ಸಿಸ್ಟಮ್ ಕ್ಯಾಟಲಾಗ್ ಟೇಬಲ್ ಅಲ್ಲ; ಇವು PGDATA/pg_xact ಡೈರೆಕ್ಟರಿಯಲ್ಲಿರುವ ಫೈಲ್‌ಗಳಾಗಿವೆ. ಅವರು ಪ್ರತಿ ವಹಿವಾಟಿಗೆ ಎರಡು ಬಿಟ್‌ಗಳನ್ನು ನಿಗದಿಪಡಿಸಿದ್ದಾರೆ: ಬದ್ಧತೆ ಮತ್ತು ಸ್ಥಗಿತಗೊಳಿಸಲಾಗಿದೆ - ಸಾಲಿನ ಆವೃತ್ತಿಯ ಹೆಡರ್‌ನಲ್ಲಿರುವಂತೆಯೇ. ಈ ಮಾಹಿತಿಯನ್ನು ಅನುಕೂಲಕ್ಕಾಗಿ ಹಲವಾರು ಫೈಲ್‌ಗಳಾಗಿ ವಿಂಗಡಿಸಲಾಗಿದೆ; ನಾವು ಘನೀಕರಿಸುವಿಕೆಯನ್ನು ಪರಿಗಣಿಸಿದಾಗ ನಾವು ಈ ಸಮಸ್ಯೆಗೆ ಹಿಂತಿರುಗುತ್ತೇವೆ. ಮತ್ತು ಈ ಫೈಲ್‌ಗಳೊಂದಿಗಿನ ಕೆಲಸವನ್ನು ಎಲ್ಲಾ ಇತರರಂತೆ ಪುಟದಿಂದ ಪುಟದಿಂದ ನಡೆಸಲಾಗುತ್ತದೆ.

ಆದ್ದರಿಂದ, XACT ನಲ್ಲಿ ವಹಿವಾಟು ಬದ್ಧವಾದಾಗ, ಈ ವಹಿವಾಟಿಗೆ ಬದ್ಧವಾದ ಬಿಟ್ ಅನ್ನು ಹೊಂದಿಸಲಾಗಿದೆ. ಮತ್ತು ಬದ್ಧತೆಯ ಸಮಯದಲ್ಲಿ ಇದು ಸಂಭವಿಸುತ್ತದೆ (ಆದರೂ ನಾವು ಪೂರ್ವ-ರೆಕಾರ್ಡಿಂಗ್ ಲಾಗ್ ಬಗ್ಗೆ ಇನ್ನೂ ಮಾತನಾಡುತ್ತಿಲ್ಲ).

ಮತ್ತೊಂದು ವಹಿವಾಟು ನಾವು ನೋಡಿದ ಟೇಬಲ್ ಪುಟವನ್ನು ಪ್ರವೇಶಿಸಿದಾಗ, ಅದು ಹಲವಾರು ಪ್ರಶ್ನೆಗಳಿಗೆ ಉತ್ತರಿಸಬೇಕಾಗುತ್ತದೆ.

  1. xmin ವಹಿವಾಟು ಪೂರ್ಣಗೊಂಡಿದೆಯೇ? ಇಲ್ಲದಿದ್ದರೆ, ಸ್ಟ್ರಿಂಗ್‌ನ ರಚಿಸಿದ ಆವೃತ್ತಿಯು ಗೋಚರಿಸಬಾರದು.
    ಈ ಪರಿಶೀಲನೆಯನ್ನು ಮತ್ತೊಂದು ರಚನೆಯನ್ನು ನೋಡುವ ಮೂಲಕ ನಿರ್ವಹಿಸಲಾಗುತ್ತದೆ, ಇದು ನಿದರ್ಶನದ ಹಂಚಿಕೆಯ ಸ್ಮರಣೆಯಲ್ಲಿದೆ ಮತ್ತು ಇದನ್ನು ProcArray ಎಂದು ಕರೆಯಲಾಗುತ್ತದೆ. ಇದು ಎಲ್ಲಾ ಸಕ್ರಿಯ ಪ್ರಕ್ರಿಯೆಗಳ ಪಟ್ಟಿಯನ್ನು ಒಳಗೊಂಡಿದೆ, ಮತ್ತು ಪ್ರತಿಯೊಂದಕ್ಕೂ ಅದರ ಪ್ರಸ್ತುತ (ಸಕ್ರಿಯ) ವಹಿವಾಟಿನ ಸಂಖ್ಯೆಯನ್ನು ಸೂಚಿಸಲಾಗುತ್ತದೆ.
  2. ಪೂರ್ಣಗೊಂಡರೆ, ನಂತರ ಹೇಗೆ - ಒಪ್ಪಿಸುವ ಅಥವಾ ರದ್ದುಗೊಳಿಸುವ ಮೂಲಕ? ರದ್ದುಗೊಳಿಸಿದರೆ, ಸಾಲು ಆವೃತ್ತಿಯು ಗೋಚರಿಸಬಾರದು.
    ಇದು ನಿಖರವಾಗಿ XACT ಆಗಿದೆ. ಆದರೆ, XACT ನ ಕೊನೆಯ ಪುಟಗಳನ್ನು RAM ನಲ್ಲಿ ಬಫರ್‌ಗಳಲ್ಲಿ ಸಂಗ್ರಹಿಸಲಾಗಿದ್ದರೂ, ಪ್ರತಿ ಬಾರಿ XACT ಅನ್ನು ಪರಿಶೀಲಿಸುವುದು ಇನ್ನೂ ದುಬಾರಿಯಾಗಿದೆ. ಆದ್ದರಿಂದ, ವಹಿವಾಟಿನ ಸ್ಥಿತಿಯನ್ನು ನಿರ್ಧರಿಸಿದ ನಂತರ, ಅದನ್ನು ಸ್ಟ್ರಿಂಗ್ ಆವೃತ್ತಿಯ xmin_committed ಮತ್ತು xmin_aborted ಬಿಟ್‌ಗಳಿಗೆ ಬರೆಯಲಾಗುತ್ತದೆ. ಈ ಬಿಟ್‌ಗಳಲ್ಲಿ ಒಂದನ್ನು ಹೊಂದಿಸಿದರೆ, xmin ವಹಿವಾಟಿನ ಸ್ಥಿತಿಯನ್ನು ತಿಳಿದಿರುವಂತೆ ಪರಿಗಣಿಸಲಾಗುತ್ತದೆ ಮತ್ತು ಮುಂದಿನ ವಹಿವಾಟು XACT ಅನ್ನು ಪ್ರವೇಶಿಸಬೇಕಾಗಿಲ್ಲ.

ಈ ಬಿಟ್‌ಗಳನ್ನು ವಹಿವಾಟಿನ ಮೂಲಕ ಏಕೆ ಹೊಂದಿಸಲಾಗಿಲ್ಲ? ಇನ್ಸರ್ಟ್ ಸಂಭವಿಸಿದಾಗ, ವಹಿವಾಟು ಯಶಸ್ವಿಯಾಗುತ್ತದೆಯೇ ಎಂದು ಇನ್ನೂ ತಿಳಿದಿಲ್ಲ. ಮತ್ತು ಒಪ್ಪಿಸುವ ಕ್ಷಣದಲ್ಲಿ, ಯಾವ ಪುಟಗಳಲ್ಲಿ ಯಾವ ಸಾಲುಗಳನ್ನು ಬದಲಾಯಿಸಲಾಗಿದೆ ಎಂಬುದು ಇನ್ನು ಮುಂದೆ ಸ್ಪಷ್ಟವಾಗಿಲ್ಲ. ಅಂತಹ ಪುಟಗಳು ಬಹಳಷ್ಟು ಇರಬಹುದು, ಮತ್ತು ಅವುಗಳನ್ನು ನೆನಪಿಟ್ಟುಕೊಳ್ಳುವುದು ಲಾಭದಾಯಕವಲ್ಲ. ಹೆಚ್ಚುವರಿಯಾಗಿ, ಕೆಲವು ಪುಟಗಳನ್ನು ಬಫರ್ ಸಂಗ್ರಹದಿಂದ ಡಿಸ್ಕ್‌ಗೆ ಹೊರಹಾಕಬಹುದು; ಬಿಟ್‌ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಅವುಗಳನ್ನು ಮತ್ತೆ ಓದುವುದು ಬದ್ಧತೆಯನ್ನು ಗಮನಾರ್ಹವಾಗಿ ನಿಧಾನಗೊಳಿಸುತ್ತದೆ.

ಉಳಿತಾಯದ ತೊಂದರೆಯೆಂದರೆ, ಬದಲಾವಣೆಯ ನಂತರ, ಯಾವುದೇ ವಹಿವಾಟು (ಒಂದು ಸರಳವಾದ ಓದುವಿಕೆ - SELECT ಅನ್ನು ನಿರ್ವಹಿಸುವುದು ಸಹ) ಬಫರ್ ಸಂಗ್ರಹದಲ್ಲಿ ಡೇಟಾ ಪುಟಗಳನ್ನು ಬದಲಾಯಿಸಲು ಪ್ರಾರಂಭಿಸಬಹುದು.

ಆದ್ದರಿಂದ, ಬದಲಾವಣೆಯನ್ನು ಸರಿಪಡಿಸೋಣ.

=> COMMIT;

ಪುಟದಲ್ಲಿ ಏನೂ ಬದಲಾಗಿಲ್ಲ (ಆದರೆ ವಹಿವಾಟಿನ ಸ್ಥಿತಿಯನ್ನು ಈಗಾಗಲೇ XACT ನಲ್ಲಿ ದಾಖಲಿಸಲಾಗಿದೆ ಎಂದು ನಮಗೆ ತಿಳಿದಿದೆ):

=> SELECT * FROM heap_page('t',0);
 ctid  | state  | xmin | xmax  | t_ctid 
-------+--------+------+-------+--------
 (0,1) | normal | 3664 | 0 (a) | (0,1)
(1 row)

ಈಗ ಮೊದಲು ಪುಟವನ್ನು ಪ್ರವೇಶಿಸುವ ವಹಿವಾಟು xmin ವಹಿವಾಟಿನ ಸ್ಥಿತಿಯನ್ನು ನಿರ್ಧರಿಸಬೇಕು ಮತ್ತು ಅದನ್ನು ಮಾಹಿತಿ ಬಿಟ್‌ಗಳಿಗೆ ಬರೆಯಬೇಕು:

=> SELECT * FROM t;
 id |  s  
----+-----
  1 | FOO
(1 row)

=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   | xmax  | t_ctid 
-------+--------+----------+-------+--------
 (0,1) | normal | 3664 (c) | 0 (a) | (0,1)
(1 row)

ಅಳಿಸಿ

ಸಾಲನ್ನು ಅಳಿಸಿದಾಗ, ಪ್ರಸ್ತುತ ಅಳಿಸುವ ವಹಿವಾಟಿನ ಸಂಖ್ಯೆಯನ್ನು ಪ್ರಸ್ತುತ ಆವೃತ್ತಿಯ xmax ಕ್ಷೇತ್ರಕ್ಕೆ ಬರೆಯಲಾಗುತ್ತದೆ ಮತ್ತು xmax_aborted ಬಿಟ್ ಅನ್ನು ತೆರವುಗೊಳಿಸಲಾಗುತ್ತದೆ.

ಸಕ್ರಿಯ ವಹಿವಾಟಿಗೆ ಅನುಗುಣವಾದ xmax ನ ಸೆಟ್ ಮೌಲ್ಯವು ಸಾಲು ಲಾಕ್ ಆಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ ಎಂಬುದನ್ನು ಗಮನಿಸಿ. ಮತ್ತೊಂದು ವಹಿವಾಟು ಈ ಸಾಲನ್ನು ನವೀಕರಿಸಲು ಅಥವಾ ಅಳಿಸಲು ಬಯಸಿದರೆ, ವಹಿವಾಟು xmax ಪೂರ್ಣಗೊಳ್ಳುವವರೆಗೆ ಕಾಯಲು ಒತ್ತಾಯಿಸಲಾಗುತ್ತದೆ. ನಾವು ನಂತರ ನಿರ್ಬಂಧಿಸುವ ಬಗ್ಗೆ ಹೆಚ್ಚು ಮಾತನಾಡುತ್ತೇವೆ. ಸದ್ಯಕ್ಕೆ, ಸಾಲು ಲಾಕ್‌ಗಳ ಸಂಖ್ಯೆಯು ಅಪರಿಮಿತವಾಗಿದೆ ಎಂಬುದನ್ನು ನಾವು ಗಮನಿಸುತ್ತೇವೆ. ಅವರು RAM ನಲ್ಲಿ ಜಾಗವನ್ನು ತೆಗೆದುಕೊಳ್ಳುವುದಿಲ್ಲ ಮತ್ತು ಸಿಸ್ಟಮ್ ಕಾರ್ಯಕ್ಷಮತೆ ಅವರ ಸಂಖ್ಯೆಯಿಂದ ಬಳಲುತ್ತಿಲ್ಲ. ನಿಜ, "ದೀರ್ಘ" ವಹಿವಾಟುಗಳು ಇತರ ಅನಾನುಕೂಲಗಳನ್ನು ಹೊಂದಿವೆ, ಆದರೆ ಅದರ ನಂತರ ಹೆಚ್ಚು.

ಸಾಲನ್ನು ಅಳಿಸೋಣ.

=> BEGIN;
=> DELETE FROM t;
=> SELECT txid_current();
 txid_current 
--------------
         3665
(1 row)

ವಹಿವಾಟಿನ ಸಂಖ್ಯೆಯನ್ನು xmax ಕ್ಷೇತ್ರದಲ್ಲಿ ಬರೆಯಲಾಗಿದೆ ಎಂದು ನಾವು ನೋಡುತ್ತೇವೆ, ಆದರೆ ಮಾಹಿತಿ ಬಿಟ್‌ಗಳನ್ನು ಹೊಂದಿಸಲಾಗಿಲ್ಲ:

=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   | xmax | t_ctid 
-------+--------+----------+------+--------
 (0,1) | normal | 3664 (c) | 3665 | (0,1)
(1 row)

ರದ್ದು

ಬದಲಾವಣೆಗಳನ್ನು ಸ್ಥಗಿತಗೊಳಿಸುವುದು ಬದ್ಧತೆಯಂತೆಯೇ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ, XACT ನಲ್ಲಿ ಮಾತ್ರ ಸ್ಥಗಿತಗೊಂಡ ಬಿಟ್ ಅನ್ನು ವಹಿವಾಟಿಗೆ ಹೊಂದಿಸಲಾಗಿದೆ. ರದ್ದುಗೊಳಿಸುವುದು ಬದ್ಧತೆಯಷ್ಟೇ ವೇಗವಾಗಿರುತ್ತದೆ. ಆಜ್ಞೆಯನ್ನು ROLLBACK ಎಂದು ಕರೆಯಲಾಗಿದ್ದರೂ, ಬದಲಾವಣೆಗಳನ್ನು ಹಿಂತಿರುಗಿಸಲಾಗುವುದಿಲ್ಲ: ಡೇಟಾ ಪುಟಗಳಲ್ಲಿ ವಹಿವಾಟು ಬದಲಾಯಿಸಲು ನಿರ್ವಹಿಸಿದ ಎಲ್ಲವೂ ಬದಲಾಗದೆ ಉಳಿಯುತ್ತದೆ.

=> ROLLBACK;
=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   | xmax | t_ctid 
-------+--------+----------+------+--------
 (0,1) | normal | 3664 (c) | 3665 | (0,1)
(1 row)

ಪುಟವನ್ನು ಪ್ರವೇಶಿಸಿದಾಗ, ಸ್ಥಿತಿಯನ್ನು ಪರಿಶೀಲಿಸಲಾಗುತ್ತದೆ ಮತ್ತು xmax_aborted ಸುಳಿವು ಬಿಟ್ ಅನ್ನು ಸಾಲಿನ ಆವೃತ್ತಿಗೆ ಹೊಂದಿಸಲಾಗುತ್ತದೆ. xmax ಸಂಖ್ಯೆಯು ಪುಟದಲ್ಲಿ ಉಳಿದಿದೆ, ಆದರೆ ಯಾರೂ ಅದನ್ನು ನೋಡುವುದಿಲ್ಲ.

=> SELECT * FROM t;
 id |  s  
----+-----
  1 | FOO
(1 row)

=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   |   xmax   | t_ctid 
-------+--------+----------+----------+--------
 (0,1) | normal | 3664 (c) | 3665 (a) | (0,1)
(1 row)

ನವೀಕರಿಸಿ

ನವೀಕರಣವು ಮೊದಲು ಸಾಲಿನ ಪ್ರಸ್ತುತ ಆವೃತ್ತಿಯನ್ನು ಅಳಿಸಿದಂತೆ ಮತ್ತು ನಂತರ ಹೊಸದನ್ನು ಸೇರಿಸಿದಂತೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ.

=> BEGIN;
=> UPDATE t SET s = 'BAR';
=> SELECT txid_current();
 txid_current 
--------------
         3666
(1 row)

ಪ್ರಶ್ನೆಯು ಒಂದು ಸಾಲನ್ನು ಉತ್ಪಾದಿಸುತ್ತದೆ (ಹೊಸ ಆವೃತ್ತಿ):

=> SELECT * FROM t;
 id |  s  
----+-----
  1 | BAR
(1 row)

ಆದರೆ ಪುಟದಲ್ಲಿ ನಾವು ಎರಡೂ ಆವೃತ್ತಿಗಳನ್ನು ನೋಡುತ್ತೇವೆ:

=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   | xmax  | t_ctid 
-------+--------+----------+-------+--------
 (0,1) | normal | 3664 (c) | 3666  | (0,2)
 (0,2) | normal | 3666     | 0 (a) | (0,2)
(2 rows)

ಅಳಿಸಲಾದ ಆವೃತ್ತಿಯನ್ನು xmax ಕ್ಷೇತ್ರದಲ್ಲಿ ಪ್ರಸ್ತುತ ವಹಿವಾಟು ಸಂಖ್ಯೆಯೊಂದಿಗೆ ಗುರುತಿಸಲಾಗಿದೆ. ಇದಲ್ಲದೆ, ಹಿಂದಿನ ವಹಿವಾಟನ್ನು ರದ್ದುಗೊಳಿಸಿರುವುದರಿಂದ ಈ ಮೌಲ್ಯವನ್ನು ಹಳೆಯದಕ್ಕೆ ಬರೆಯಲಾಗಿದೆ. ಮತ್ತು xmax_aborted ಬಿಟ್ ಅನ್ನು ತೆರವುಗೊಳಿಸಲಾಗಿದೆ ಏಕೆಂದರೆ ಪ್ರಸ್ತುತ ವಹಿವಾಟಿನ ಸ್ಥಿತಿ ಇನ್ನೂ ತಿಳಿದಿಲ್ಲ.

ಸಾಲಿನ ಮೊದಲ ಆವೃತ್ತಿಯು ಈಗ ಎರಡನೆಯದನ್ನು (t_ctid ಕ್ಷೇತ್ರ) ಹೊಸದೆಂದು ಉಲ್ಲೇಖಿಸುತ್ತದೆ.

ಎರಡನೇ ಸೂಚ್ಯಂಕವು ಸೂಚ್ಯಂಕ ಪುಟದಲ್ಲಿ ಕಾಣಿಸಿಕೊಳ್ಳುತ್ತದೆ ಮತ್ತು ಎರಡನೇ ಸಾಲು ಟೇಬಲ್ ಪುಟದಲ್ಲಿ ಎರಡನೇ ಆವೃತ್ತಿಯನ್ನು ಉಲ್ಲೇಖಿಸುತ್ತದೆ.

ಅಳಿಸುವಿಕೆಯಂತೆಯೇ, ಸಾಲಿನ ಮೊದಲ ಆವೃತ್ತಿಯಲ್ಲಿನ xmax ಮೌಲ್ಯವು ಸಾಲು ಲಾಕ್ ಆಗಿದೆ ಎಂಬುದರ ಸೂಚನೆಯಾಗಿದೆ.

ಸರಿ, ವ್ಯವಹಾರವನ್ನು ಪೂರ್ಣಗೊಳಿಸೋಣ.

=> COMMIT;

ಸೂಚ್ಯಂಕಗಳು

ಇಲ್ಲಿಯವರೆಗೆ ನಾವು ಟೇಬಲ್ ಪುಟಗಳ ಬಗ್ಗೆ ಮಾತ್ರ ಮಾತನಾಡಿದ್ದೇವೆ. ಸೂಚ್ಯಂಕಗಳ ಒಳಗೆ ಏನಾಗುತ್ತದೆ?

ನಿರ್ದಿಷ್ಟ ಪ್ರಕಾರದ ಸೂಚ್ಯಂಕವನ್ನು ಅವಲಂಬಿಸಿ ಸೂಚ್ಯಂಕ ಪುಟಗಳಲ್ಲಿನ ಮಾಹಿತಿಯು ಬಹಳವಾಗಿ ಬದಲಾಗುತ್ತದೆ. ಮತ್ತು ಒಂದು ರೀತಿಯ ಸೂಚ್ಯಂಕವು ವಿವಿಧ ರೀತಿಯ ಪುಟಗಳನ್ನು ಹೊಂದಿದೆ. ಉದಾಹರಣೆಗೆ, ಬಿ-ಟ್ರೀ ಮೆಟಾಡೇಟಾ ಪುಟ ಮತ್ತು "ನಿಯಮಿತ" ಪುಟಗಳನ್ನು ಹೊಂದಿದೆ.

ಆದಾಗ್ಯೂ, ಪುಟವು ಸಾಮಾನ್ಯವಾಗಿ ಸಾಲುಗಳು ಮತ್ತು ಸಾಲುಗಳಿಗೆ ಪಾಯಿಂಟರ್‌ಗಳ ಒಂದು ಶ್ರೇಣಿಯನ್ನು ಹೊಂದಿರುತ್ತದೆ (ಕೇವಲ ಟೇಬಲ್ ಪುಟದಂತೆಯೇ). ಹೆಚ್ಚುವರಿಯಾಗಿ, ಪುಟದ ಕೊನೆಯಲ್ಲಿ ವಿಶೇಷ ಡೇಟಾಕ್ಕಾಗಿ ಸ್ಥಳಾವಕಾಶವಿದೆ.

ಸೂಚ್ಯಂಕಗಳಲ್ಲಿನ ಸಾಲುಗಳು ಸೂಚ್ಯಂಕದ ಪ್ರಕಾರವನ್ನು ಅವಲಂಬಿಸಿ ವಿಭಿನ್ನ ರಚನೆಗಳನ್ನು ಹೊಂದಬಹುದು. ಉದಾಹರಣೆಗೆ, ಬಿ-ಟ್ರೀಗಾಗಿ, ಲೀಫ್ ಪುಟಗಳಿಗೆ ಸಂಬಂಧಿಸಿದ ಸಾಲುಗಳು ಸೂಚ್ಯಂಕ ಕೀ ಮೌಲ್ಯವನ್ನು ಮತ್ತು ಅನುಗುಣವಾದ ಟೇಬಲ್ ಸಾಲಿಗೆ ಉಲ್ಲೇಖವನ್ನು (ctid) ಒಳಗೊಂಡಿರುತ್ತವೆ. ಸಾಮಾನ್ಯವಾಗಿ, ಸೂಚ್ಯಂಕವನ್ನು ಸಂಪೂರ್ಣವಾಗಿ ವಿಭಿನ್ನ ರೀತಿಯಲ್ಲಿ ರಚಿಸಬಹುದು.

ಯಾವುದೇ ಪ್ರಕಾರದ ಸೂಚ್ಯಂಕಗಳಲ್ಲಿ ಯಾವುದೇ ಸಾಲಿನ ಆವೃತ್ತಿಗಳಿಲ್ಲ ಎಂಬುದು ಅತ್ಯಂತ ಮುಖ್ಯವಾದ ಅಂಶವಾಗಿದೆ. ಸರಿ, ಅಥವಾ ಪ್ರತಿ ಸಾಲನ್ನು ನಿಖರವಾಗಿ ಒಂದು ಆವೃತ್ತಿಯಿಂದ ಪ್ರತಿನಿಧಿಸಲಾಗುತ್ತದೆ ಎಂದು ನಾವು ಊಹಿಸಬಹುದು. ಬೇರೆ ರೀತಿಯಲ್ಲಿ ಹೇಳುವುದಾದರೆ, ಇಂಡೆಕ್ಸ್ ಸಾಲು ಹೆಡರ್‌ನಲ್ಲಿ ಯಾವುದೇ xmin ಮತ್ತು xmax ಕ್ಷೇತ್ರಗಳಿಲ್ಲ. ಸೂಚ್ಯಂಕದಿಂದ ಲಿಂಕ್‌ಗಳು ಸಾಲುಗಳ ಎಲ್ಲಾ ಟೇಬಲ್ ಆವೃತ್ತಿಗಳಿಗೆ ಕಾರಣವಾಗುತ್ತವೆ ಎಂದು ನಾವು ಊಹಿಸಬಹುದು - ಆದ್ದರಿಂದ ಟೇಬಲ್ ಅನ್ನು ನೋಡುವ ಮೂಲಕ ಮಾತ್ರ ವಹಿವಾಟು ಯಾವ ಆವೃತ್ತಿಯನ್ನು ನೋಡುತ್ತದೆ ಎಂಬುದನ್ನು ನೀವು ಲೆಕ್ಕಾಚಾರ ಮಾಡಬಹುದು. (ಯಾವಾಗಲೂ, ಇದು ಸಂಪೂರ್ಣ ಸತ್ಯವಲ್ಲ. ಕೆಲವು ಸಂದರ್ಭಗಳಲ್ಲಿ, ಗೋಚರತೆಯ ನಕ್ಷೆಯು ಪ್ರಕ್ರಿಯೆಯನ್ನು ಉತ್ತಮಗೊಳಿಸಬಹುದು, ಆದರೆ ನಾವು ಇದನ್ನು ನಂತರ ಹೆಚ್ಚು ವಿವರವಾಗಿ ನೋಡುತ್ತೇವೆ.)

ಅದೇ ಸಮಯದಲ್ಲಿ, ಸೂಚ್ಯಂಕ ಪುಟದಲ್ಲಿ ನಾವು ಪ್ರಸ್ತುತ ಮತ್ತು ಹಳೆಯ ಎರಡೂ ಆವೃತ್ತಿಗಳಿಗೆ ಪಾಯಿಂಟರ್‌ಗಳನ್ನು ಕಂಡುಕೊಳ್ಳುತ್ತೇವೆ:

=> SELECT itemoffset, ctid FROM bt_page_items('t_s_idx',1);
 itemoffset | ctid  
------------+-------
          1 | (0,2)
          2 | (0,1)
(2 rows)

ವರ್ಚುವಲ್ ವಹಿವಾಟುಗಳು

ಪ್ರಾಯೋಗಿಕವಾಗಿ, PostgreSQL ವಹಿವಾಟು ಸಂಖ್ಯೆಗಳನ್ನು "ಉಳಿಸಲು" ಅನುಮತಿಸುವ ಆಪ್ಟಿಮೈಸೇಶನ್‌ಗಳನ್ನು ಬಳಸುತ್ತದೆ.

ವಹಿವಾಟು ಡೇಟಾವನ್ನು ಮಾತ್ರ ಓದಿದರೆ, ಅದು ಸಾಲು ಆವೃತ್ತಿಗಳ ಗೋಚರತೆಯ ಮೇಲೆ ಯಾವುದೇ ಪರಿಣಾಮ ಬೀರುವುದಿಲ್ಲ. ಆದ್ದರಿಂದ, ಸೇವಾ ಪ್ರಕ್ರಿಯೆಯು ಮೊದಲು ವಹಿವಾಟಿಗೆ ವರ್ಚುವಲ್ xid ಅನ್ನು ನೀಡುತ್ತದೆ. ಸಂಖ್ಯೆಯು ಪ್ರಕ್ರಿಯೆ ID ಮತ್ತು ಅನುಕ್ರಮ ಸಂಖ್ಯೆಯನ್ನು ಒಳಗೊಂಡಿರುತ್ತದೆ.

ಈ ಸಂಖ್ಯೆಯನ್ನು ನೀಡುವುದರಿಂದ ಎಲ್ಲಾ ಪ್ರಕ್ರಿಯೆಗಳ ನಡುವೆ ಸಿಂಕ್ರೊನೈಸೇಶನ್ ಅಗತ್ಯವಿಲ್ಲ ಮತ್ತು ಆದ್ದರಿಂದ ಇದು ತುಂಬಾ ವೇಗವಾಗಿರುತ್ತದೆ. ನಾವು ಘನೀಕರಣದ ಬಗ್ಗೆ ಮಾತನಾಡುವಾಗ ವರ್ಚುವಲ್ ಸಂಖ್ಯೆಗಳನ್ನು ಬಳಸುವ ಇನ್ನೊಂದು ಕಾರಣದೊಂದಿಗೆ ನಾವು ಪರಿಚಯ ಮಾಡಿಕೊಳ್ಳುತ್ತೇವೆ.

ಡೇಟಾ ಸ್ನ್ಯಾಪ್‌ಶಾಟ್‌ಗಳಲ್ಲಿ ವರ್ಚುವಲ್ ಸಂಖ್ಯೆಗಳನ್ನು ಯಾವುದೇ ರೀತಿಯಲ್ಲಿ ಗಣನೆಗೆ ತೆಗೆದುಕೊಳ್ಳುವುದಿಲ್ಲ.

ವಿಭಿನ್ನ ಸಮಯಗಳಲ್ಲಿ, ಸಿಸ್ಟಮ್‌ನಲ್ಲಿ ಈಗಾಗಲೇ ಬಳಸಿದ ಸಂಖ್ಯೆಗಳೊಂದಿಗೆ ವರ್ಚುವಲ್ ವಹಿವಾಟುಗಳು ಇರಬಹುದು ಮತ್ತು ಇದು ಸಾಮಾನ್ಯವಾಗಿದೆ. ಆದರೆ ಅಂತಹ ಸಂಖ್ಯೆಯನ್ನು ಡೇಟಾ ಪುಟಗಳಲ್ಲಿ ಬರೆಯಲಾಗುವುದಿಲ್ಲ, ಏಕೆಂದರೆ ಮುಂದಿನ ಬಾರಿ ಪುಟವನ್ನು ಪ್ರವೇಶಿಸಿದಾಗ ಅದು ಎಲ್ಲಾ ಅರ್ಥವನ್ನು ಕಳೆದುಕೊಳ್ಳಬಹುದು.

=> BEGIN;
=> SELECT txid_current_if_assigned();
 txid_current_if_assigned 
--------------------------
                         
(1 row)

ವಹಿವಾಟು ಡೇಟಾವನ್ನು ಬದಲಾಯಿಸಲು ಪ್ರಾರಂಭಿಸಿದರೆ, ಅದಕ್ಕೆ ನಿಜವಾದ, ಅನನ್ಯ ವಹಿವಾಟು ಸಂಖ್ಯೆಯನ್ನು ನೀಡಲಾಗುತ್ತದೆ.

=> UPDATE accounts SET amount = amount - 1.00;
=> SELECT txid_current_if_assigned();
 txid_current_if_assigned 
--------------------------
                     3667
(1 row)

=> COMMIT;

ನೆಸ್ಟೆಡ್ ವಹಿವಾಟುಗಳು

ಅಂಕಗಳನ್ನು ಉಳಿಸಿ

SQL ನಲ್ಲಿ ವ್ಯಾಖ್ಯಾನಿಸಲಾಗಿದೆ ಅಂಕಗಳನ್ನು ಉಳಿಸಿ (ಸೇವ್ ಪಾಯಿಂಟ್), ಇದು ವಹಿವಾಟಿನ ಭಾಗವನ್ನು ಸಂಪೂರ್ಣವಾಗಿ ಅಡ್ಡಿಪಡಿಸದೆಯೇ ರದ್ದುಗೊಳಿಸಲು ನಿಮಗೆ ಅನುಮತಿಸುತ್ತದೆ. ಆದರೆ ಇದು ಮೇಲಿನ ರೇಖಾಚಿತ್ರಕ್ಕೆ ಹೊಂದಿಕೆಯಾಗುವುದಿಲ್ಲ, ಏಕೆಂದರೆ ವಹಿವಾಟು ಅದರ ಎಲ್ಲಾ ಬದಲಾವಣೆಗಳಿಗೆ ಒಂದೇ ಸ್ಥಿತಿಯನ್ನು ಹೊಂದಿದೆ ಮತ್ತು ಭೌತಿಕವಾಗಿ ಯಾವುದೇ ಡೇಟಾವನ್ನು ಹಿಂತಿರುಗಿಸಲಾಗುವುದಿಲ್ಲ.

ಈ ಕಾರ್ಯವನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸಲು, ಸೇವ್‌ಪಾಯಿಂಟ್‌ನೊಂದಿಗೆ ವ್ಯವಹಾರವನ್ನು ಹಲವಾರು ಪ್ರತ್ಯೇಕಗಳಾಗಿ ವಿಂಗಡಿಸಲಾಗಿದೆ ನೆಸ್ಟೆಡ್ ವಹಿವಾಟುಗಳು (ಉಪವರ್ತನೆ), ಅದರ ಸ್ಥಿತಿಯನ್ನು ಪ್ರತ್ಯೇಕವಾಗಿ ನಿರ್ವಹಿಸಬಹುದು.

ನೆಸ್ಟೆಡ್ ವಹಿವಾಟುಗಳು ತಮ್ಮದೇ ಆದ ಸಂಖ್ಯೆಯನ್ನು ಹೊಂದಿವೆ (ಮುಖ್ಯ ವಹಿವಾಟಿನ ಸಂಖ್ಯೆಗಿಂತ ಹೆಚ್ಚಿನದು). ನೆಸ್ಟೆಡ್ ವಹಿವಾಟುಗಳ ಸ್ಥಿತಿಯನ್ನು ಸಾಮಾನ್ಯ ರೀತಿಯಲ್ಲಿ XACT ನಲ್ಲಿ ದಾಖಲಿಸಲಾಗಿದೆ, ಆದರೆ ಅಂತಿಮ ಸ್ಥಿತಿಯು ಮುಖ್ಯ ವಹಿವಾಟಿನ ಸ್ಥಿತಿಯನ್ನು ಅವಲಂಬಿಸಿರುತ್ತದೆ: ಅದನ್ನು ರದ್ದುಗೊಳಿಸಿದರೆ, ಎಲ್ಲಾ ನೆಸ್ಟೆಡ್ ವಹಿವಾಟುಗಳನ್ನು ಸಹ ರದ್ದುಗೊಳಿಸಲಾಗುತ್ತದೆ.

ವಹಿವಾಟಿನ ಗೂಡುಕಟ್ಟುವ ಕುರಿತು ಮಾಹಿತಿಯನ್ನು PGDATA/pg_subtrans ಡೈರೆಕ್ಟರಿಯಲ್ಲಿ ಫೈಲ್‌ಗಳಲ್ಲಿ ಸಂಗ್ರಹಿಸಲಾಗಿದೆ. XACT ಬಫರ್‌ಗಳ ರೀತಿಯಲ್ಲಿಯೇ ಆಯೋಜಿಸಲಾದ ನಿದರ್ಶನದ ಹಂಚಿಕೆಯ ಮೆಮೊರಿಯಲ್ಲಿ ಬಫರ್‌ಗಳ ಮೂಲಕ ಫೈಲ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಲಾಗುತ್ತದೆ.

ನೆಸ್ಟೆಡ್ ವಹಿವಾಟುಗಳನ್ನು ಸ್ವಾಯತ್ತ ವಹಿವಾಟುಗಳೊಂದಿಗೆ ಗೊಂದಲಗೊಳಿಸಬೇಡಿ. ಸ್ವಾಯತ್ತ ವಹಿವಾಟುಗಳು ಯಾವುದೇ ರೀತಿಯಲ್ಲಿ ಪರಸ್ಪರ ಅವಲಂಬಿಸಿರುವುದಿಲ್ಲ, ಆದರೆ ನೆಸ್ಟೆಡ್ ವಹಿವಾಟುಗಳು ಮಾಡುತ್ತವೆ. ನಿಯಮಿತವಾದ PostgreSQL ನಲ್ಲಿ ಯಾವುದೇ ಸ್ವಾಯತ್ತ ವಹಿವಾಟುಗಳಿಲ್ಲ, ಮತ್ತು, ಬಹುಶಃ, ಅತ್ಯುತ್ತಮವಾದವುಗಳಿಗೆ: ಅವುಗಳು ಬಹಳ ವಿರಳವಾಗಿ ಬೇಕಾಗುತ್ತದೆ, ಮತ್ತು ಇತರ DBMS ಗಳಲ್ಲಿ ಅವರ ಉಪಸ್ಥಿತಿಯು ನಿಂದನೆಯನ್ನು ಪ್ರಚೋದಿಸುತ್ತದೆ, ಇದರಿಂದ ಪ್ರತಿಯೊಬ್ಬರೂ ಬಳಲುತ್ತಿದ್ದಾರೆ.

ಟೇಬಲ್ ಅನ್ನು ತೆರವುಗೊಳಿಸಿ, ವಹಿವಾಟು ಆರಂಭಿಸೋಣ ಮತ್ತು ಸಾಲನ್ನು ಸೇರಿಸೋಣ:

=> TRUNCATE TABLE t;
=> BEGIN;
=> INSERT INTO t(s) VALUES ('FOO');
=> SELECT txid_current();
 txid_current 
--------------
         3669
(1 row)

=> SELECT xmin, xmax, * FROM t;
 xmin | xmax | id |  s  
------+------+----+-----
 3669 |    0 |  2 | FOO
(1 row)

=> SELECT * FROM heap_page('t',0);
 ctid  | state  | xmin | xmax  | t_ctid 
-------+--------+------+-------+--------
 (0,1) | normal | 3669 | 0 (a) | (0,1)
(1 row)

ಈಗ ಸೇವ್ ಪಾಯಿಂಟ್ ಅನ್ನು ಹಾಕೋಣ ಮತ್ತು ಇನ್ನೊಂದು ಸಾಲನ್ನು ಸೇರಿಸೋಣ.

=> SAVEPOINT sp;
=> INSERT INTO t(s) VALUES ('XYZ');
=> SELECT txid_current();
 txid_current 
--------------
         3669
(1 row)

txid_current() ಕಾರ್ಯವು ಮುಖ್ಯ ವಹಿವಾಟು ಸಂಖ್ಯೆಯನ್ನು ಹಿಂದಿರುಗಿಸುತ್ತದೆ, ನೆಸ್ಟೆಡ್ ವಹಿವಾಟಿನ ಸಂಖ್ಯೆಯನ್ನು ಅಲ್ಲ.

=> SELECT xmin, xmax, * FROM t;
 xmin | xmax | id |  s  
------+------+----+-----
 3669 |    0 |  2 | FOO
 3670 |    0 |  3 | XYZ
(2 rows)

=> SELECT * FROM heap_page('t',0);
 ctid  | state  | xmin | xmax  | t_ctid 
-------+--------+------+-------+--------
 (0,1) | normal | 3669 | 0 (a) | (0,1)
 (0,2) | normal | 3670 | 0 (a) | (0,2)
(2 rows)

ಸೇವ್ ಪಾಯಿಂಟ್‌ಗೆ ಹಿಂತಿರುಗಿ ಮತ್ತು ಮೂರನೇ ಸಾಲನ್ನು ಸೇರಿಸೋಣ.

=> ROLLBACK TO sp;
=> INSERT INTO t(s) VALUES ('BAR');
=> SELECT xmin, xmax, * FROM t;
 xmin | xmax | id |  s  
------+------+----+-----
 3669 |    0 |  2 | FOO
 3671 |    0 |  4 | BAR
(2 rows)

=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   | xmax  | t_ctid 
-------+--------+----------+-------+--------
 (0,1) | normal | 3669     | 0 (a) | (0,1)
 (0,2) | normal | 3670 (a) | 0 (a) | (0,2)
 (0,3) | normal | 3671     | 0 (a) | (0,3)
(3 rows)

ಪುಟದಲ್ಲಿ ನಾವು ರದ್ದುಗೊಳಿಸಲಾದ ನೆಸ್ಟೆಡ್ ವಹಿವಾಟಿನಿಂದ ಸೇರಿಸಲಾದ ಸಾಲನ್ನು ನೋಡುವುದನ್ನು ಮುಂದುವರಿಸುತ್ತೇವೆ.

ನಾವು ಬದಲಾವಣೆಗಳನ್ನು ಸರಿಪಡಿಸುತ್ತೇವೆ.

=> COMMIT;
=> SELECT xmin, xmax, * FROM t;
 xmin | xmax | id |  s  
------+------+----+-----
 3669 |    0 |  2 | FOO
 3671 |    0 |  4 | BAR
(2 rows)

=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   | xmax  | t_ctid 
-------+--------+----------+-------+--------
 (0,1) | normal | 3669 (c) | 0 (a) | (0,1)
 (0,2) | normal | 3670 (a) | 0 (a) | (0,2)
 (0,3) | normal | 3671 (c) | 0 (a) | (0,3)
(3 rows)

ಪ್ರತಿ ನೆಸ್ಟೆಡ್ ವಹಿವಾಟು ತನ್ನದೇ ಆದ ಸ್ಥಿತಿಯನ್ನು ಹೊಂದಿದೆ ಎಂದು ಈಗ ನೀವು ಸ್ಪಷ್ಟವಾಗಿ ನೋಡಬಹುದು.

ನೆಸ್ಟೆಡ್ ವಹಿವಾಟುಗಳನ್ನು SQL ನಲ್ಲಿ ಸ್ಪಷ್ಟವಾಗಿ ಬಳಸಲಾಗುವುದಿಲ್ಲ ಎಂಬುದನ್ನು ಗಮನಿಸಿ, ಅಂದರೆ, ಪ್ರಸ್ತುತವನ್ನು ಪೂರ್ಣಗೊಳಿಸದೆ ನೀವು ಹೊಸ ವಹಿವಾಟನ್ನು ಪ್ರಾರಂಭಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಸೇವ್ ಪಾಯಿಂಟ್‌ಗಳನ್ನು ಬಳಸುವಾಗ, ಹಾಗೆಯೇ PL/pgSQL ವಿನಾಯಿತಿಗಳನ್ನು ನಿರ್ವಹಿಸುವಾಗ ಮತ್ತು ಹಲವಾರು ಇತರ, ಹೆಚ್ಚು ವಿಲಕ್ಷಣ ಸಂದರ್ಭಗಳಲ್ಲಿ ಈ ಕಾರ್ಯವಿಧಾನವನ್ನು ಸೂಚ್ಯವಾಗಿ ಸಕ್ರಿಯಗೊಳಿಸಲಾಗುತ್ತದೆ.

=> BEGIN;
BEGIN
=> BEGIN;
WARNING:  there is already a transaction in progress
BEGIN
=> COMMIT;
COMMIT
=> COMMIT;
WARNING:  there is no transaction in progress
COMMIT

ಕಾರ್ಯಾಚರಣೆಗಳ ದೋಷಗಳು ಮತ್ತು ಪರಮಾಣು

ಕಾರ್ಯಾಚರಣೆಯನ್ನು ನಿರ್ವಹಿಸುವಾಗ ದೋಷ ಸಂಭವಿಸಿದರೆ ಏನಾಗುತ್ತದೆ? ಉದಾಹರಣೆಗೆ, ಈ ರೀತಿ:

=> BEGIN;
=> SELECT * FROM t;
 id |  s  
----+-----
  2 | FOO
  4 | BAR
(2 rows)

=> UPDATE t SET s = repeat('X', 1/(id-4));
ERROR:  division by zero

ದೋಷ ಕಂಡುಬಂದಿದೆ. ಈಗ ವಹಿವಾಟನ್ನು ಸ್ಥಗಿತಗೊಳಿಸಲಾಗಿದೆ ಎಂದು ಪರಿಗಣಿಸಲಾಗಿದೆ ಮತ್ತು ಅದರಲ್ಲಿ ಯಾವುದೇ ಕಾರ್ಯಾಚರಣೆಗಳನ್ನು ಅನುಮತಿಸಲಾಗುವುದಿಲ್ಲ:

=> SELECT * FROM t;
ERROR:  current transaction is aborted, commands ignored until end of transaction block

ಮತ್ತು ನೀವು ಬದಲಾವಣೆಗಳನ್ನು ಮಾಡಲು ಪ್ರಯತ್ನಿಸಿದರೂ ಸಹ, PostgreSQL ಸ್ಥಗಿತವನ್ನು ವರದಿ ಮಾಡುತ್ತದೆ:

=> COMMIT;
ROLLBACK

ವೈಫಲ್ಯದ ನಂತರ ವ್ಯವಹಾರವನ್ನು ಏಕೆ ಮುಂದುವರಿಸಬಾರದು? ಸಂಗತಿಯೆಂದರೆ, ಬದಲಾವಣೆಗಳ ಭಾಗಕ್ಕೆ ನಾವು ಪ್ರವೇಶವನ್ನು ಪಡೆಯುವ ರೀತಿಯಲ್ಲಿ ದೋಷವು ಉದ್ಭವಿಸಬಹುದು - ವಹಿವಾಟಿನ ಪರಮಾಣುತ್ವವು ಸಹ ಅಲ್ಲ, ಆದರೆ ಆಪರೇಟರ್ ಉಲ್ಲಂಘಿಸಲ್ಪಡುತ್ತದೆ. ನಮ್ಮ ಉದಾಹರಣೆಯಲ್ಲಿರುವಂತೆ, ದೋಷದ ಮೊದಲು ಆಪರೇಟರ್ ಒಂದು ಸಾಲನ್ನು ನವೀಕರಿಸಲು ನಿರ್ವಹಿಸುತ್ತಿದ್ದ:

=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   | xmax  | t_ctid 
-------+--------+----------+-------+--------
 (0,1) | normal | 3669 (c) | 3672  | (0,4)
 (0,2) | normal | 3670 (a) | 0 (a) | (0,2)
 (0,3) | normal | 3671 (c) | 0 (a) | (0,3)
 (0,4) | normal | 3672     | 0 (a) | (0,4)
(4 rows)

psql ಒಂದು ಮೋಡ್ ಅನ್ನು ಹೊಂದಿದೆ ಎಂದು ಹೇಳಬೇಕು ಅದು ವಿಫಲವಾದ ಆಪರೇಟರ್‌ನ ಕ್ರಮಗಳನ್ನು ಹಿಂದಕ್ಕೆ ತಿರುಗಿಸಿದಂತೆ ವ್ಯವಹಾರವನ್ನು ವಿಫಲವಾದ ನಂತರವೂ ಮುಂದುವರಿಸಲು ಅನುಮತಿಸುತ್ತದೆ.

=> set ON_ERROR_ROLLBACK on
=> BEGIN;
=> SELECT * FROM t;
 id |  s  
----+-----
  2 | FOO
  4 | BAR
(2 rows)

=> UPDATE t SET s = repeat('X', 1/(id-4));
ERROR:  division by zero

=> SELECT * FROM t;
 id |  s  
----+-----
  2 | FOO
  4 | BAR
(2 rows)

=> COMMIT;

ಈ ಕ್ರಮದಲ್ಲಿ, psql ವಾಸ್ತವವಾಗಿ ಪ್ರತಿ ಆಜ್ಞೆಯ ಮೊದಲು ಒಂದು ಸೂಚ್ಯ ಸೇವ್ ಪಾಯಿಂಟ್ ಅನ್ನು ಇರಿಸುತ್ತದೆ ಎಂದು ಊಹಿಸಲು ಕಷ್ಟವಾಗುವುದಿಲ್ಲ, ಮತ್ತು ವೈಫಲ್ಯದ ಸಂದರ್ಭದಲ್ಲಿ ಅದಕ್ಕೆ ಹಿಂತಿರುಗುವಿಕೆಯನ್ನು ಪ್ರಾರಂಭಿಸುತ್ತದೆ. ಈ ಮೋಡ್ ಅನ್ನು ಪೂರ್ವನಿಯೋಜಿತವಾಗಿ ಬಳಸಲಾಗುವುದಿಲ್ಲ, ಏಕೆಂದರೆ ಸೇವ್‌ಪಾಯಿಂಟ್‌ಗಳನ್ನು ಹೊಂದಿಸುವುದು (ಅವುಗಳಿಗೆ ಹಿಂತಿರುಗದೆ ಸಹ) ಗಮನಾರ್ಹವಾದ ಓವರ್‌ಹೆಡ್ ಅನ್ನು ಒಳಗೊಂಡಿರುತ್ತದೆ.

ಮುಂದುವರಿಕೆ.

ಮೂಲ: www.habr.com

ಕಾಮೆಂಟ್ ಅನ್ನು ಸೇರಿಸಿ