PostgreSQL ಆಂಟಿಪ್ಯಾಟರ್ನ್‌ಗಳು: ಹಾನಿಕಾರಕ ಸೇರ್ಪಡೆಗಳು ಮತ್ತು ORಗಳು

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

PG ಯ ಕೆಲವು ನಂತರದ ಆವೃತ್ತಿಗಳಲ್ಲಿ, ಶೆಡ್ಯೂಲರ್ ಚುರುಕಾದಾಗ ಪರಿಸ್ಥಿತಿಯು ಬದಲಾಗಬಹುದು, ಆದರೆ 9.4/9.6 ಕ್ಕೆ ಇಲ್ಲಿ ಉದಾಹರಣೆಗಳಲ್ಲಿರುವಂತೆ ಇದು ಸರಿಸುಮಾರು ಒಂದೇ ರೀತಿ ಕಾಣುತ್ತದೆ.

ನಾವು ನಿಜವಾದ ವಿನಂತಿಯನ್ನು ತೆಗೆದುಕೊಳ್ಳೋಣ:

SELECT
  TRUE
FROM
  "Документ" d
INNER JOIN
  "ДокументРасширение" doc_ex
    USING("@Документ")
INNER JOIN
  "ТипДокумента" t_doc ON
    t_doc."@ТипДокумента" = d."ТипДокумента"
WHERE
  (d."Лицо3" = 19091 or d."Сотрудник" = 19091) AND
  d."$Черновик" IS NULL AND
  d."Удален" IS NOT TRUE AND
  doc_ex."Состояние"[1] IS TRUE AND
  t_doc."ТипДокумента" = 'ПланРабот'
LIMIT 1;

ಕೋಷ್ಟಕ ಮತ್ತು ಕ್ಷೇತ್ರದ ಹೆಸರುಗಳ ಬಗ್ಗೆಕ್ಷೇತ್ರಗಳು ಮತ್ತು ಕೋಷ್ಟಕಗಳ "ರಷ್ಯನ್" ಹೆಸರುಗಳನ್ನು ವಿಭಿನ್ನವಾಗಿ ಪರಿಗಣಿಸಬಹುದು, ಆದರೆ ಇದು ರುಚಿಯ ವಿಷಯವಾಗಿದೆ. ಏಕೆಂದರೆ ದಿ ಇಲ್ಲಿ ಟೆನ್ಸರ್ ನಲ್ಲಿ ಯಾವುದೇ ವಿದೇಶಿ ಡೆವಲಪರ್‌ಗಳಿಲ್ಲ, ಮತ್ತು PostgreSQL ಅವರು ಚಿತ್ರಲಿಪಿಗಳಲ್ಲಿಯೂ ಸಹ ಹೆಸರುಗಳನ್ನು ನೀಡಲು ಅನುಮತಿಸುತ್ತದೆ ಉಲ್ಲೇಖಗಳಲ್ಲಿ ಲಗತ್ತಿಸಲಾಗಿದೆ, ನಂತರ ನಾವು ವಸ್ತುಗಳನ್ನು ನಿಸ್ಸಂದಿಗ್ಧವಾಗಿ ಮತ್ತು ಸ್ಪಷ್ಟವಾಗಿ ಹೆಸರಿಸಲು ಬಯಸುತ್ತೇವೆ ಇದರಿಂದ ಯಾವುದೇ ವ್ಯತ್ಯಾಸಗಳಿಲ್ಲ.
ಫಲಿತಾಂಶದ ಯೋಜನೆಯನ್ನು ನೋಡೋಣ:
PostgreSQL ಆಂಟಿಪ್ಯಾಟರ್ನ್‌ಗಳು: ಹಾನಿಕಾರಕ ಸೇರ್ಪಡೆಗಳು ಮತ್ತು ORಗಳು
[explain.tensor.ru ನೋಡಿ]

144ms ಮತ್ತು ಬಹುತೇಕ 53K ಬಫರ್‌ಗಳು - ಅಂದರೆ, 400MB ಗಿಂತ ಹೆಚ್ಚು ಡೇಟಾ! ಮತ್ತು ನಮ್ಮ ವಿನಂತಿಯ ಸಮಯದಲ್ಲಿ ಅವೆಲ್ಲವೂ ಸಂಗ್ರಹದಲ್ಲಿದ್ದರೆ ನಾವು ಅದೃಷ್ಟಶಾಲಿಯಾಗುತ್ತೇವೆ, ಇಲ್ಲದಿದ್ದರೆ ಡಿಸ್ಕ್ನಿಂದ ಓದಿದಾಗ ಅದು ಹಲವು ಪಟ್ಟು ಹೆಚ್ಚು ಸಮಯ ತೆಗೆದುಕೊಳ್ಳುತ್ತದೆ.

ಅಲ್ಗಾರಿದಮ್ ಅತ್ಯಂತ ಮುಖ್ಯವಾಗಿದೆ!

ಯಾವುದೇ ವಿನಂತಿಯನ್ನು ಹೇಗಾದರೂ ಆಪ್ಟಿಮೈಜ್ ಮಾಡಲು, ಅದು ಏನು ಮಾಡಬೇಕೆಂದು ನೀವು ಮೊದಲು ಅರ್ಥಮಾಡಿಕೊಳ್ಳಬೇಕು.
ಡೇಟಾಬೇಸ್ ರಚನೆಯ ಅಭಿವೃದ್ಧಿಯನ್ನು ಇದೀಗ ಈ ಲೇಖನದ ವ್ಯಾಪ್ತಿಯಿಂದ ಹೊರಗಿಡೋಣ ಮತ್ತು ನಾವು ತುಲನಾತ್ಮಕವಾಗಿ "ಅಗ್ಗವಾಗಿ" ಮಾಡಬಹುದು ಎಂದು ಒಪ್ಪಿಕೊಳ್ಳೋಣ. ವಿನಂತಿಯನ್ನು ಪುನಃ ಬರೆಯಿರಿ ಮತ್ತು/ಅಥವಾ ನಮಗೆ ಅಗತ್ಯವಿರುವ ಕೆಲವು ವಸ್ತುಗಳ ಆಧಾರದ ಮೇಲೆ ಸುತ್ತಿಕೊಳ್ಳಿ ಸೂಚ್ಯಂಕಗಳು.

ಆದ್ದರಿಂದ ವಿನಂತಿ:
- ಕನಿಷ್ಠ ಕೆಲವು ದಾಖಲೆಗಳ ಅಸ್ತಿತ್ವವನ್ನು ಪರಿಶೀಲಿಸುತ್ತದೆ
- ನಮಗೆ ಅಗತ್ಯವಿರುವ ಮತ್ತು ಒಂದು ನಿರ್ದಿಷ್ಟ ಪ್ರಕಾರದ ಸ್ಥಿತಿಯಲ್ಲಿ
- ಅಲ್ಲಿ ಲೇಖಕ ಅಥವಾ ಪ್ರದರ್ಶಕ ನಮಗೆ ಅಗತ್ಯವಿರುವ ಉದ್ಯೋಗಿ

ಸೇರ್ಪಡೆ + ಮಿತಿ 1

ಹೆಚ್ಚಿನ ಸಂಖ್ಯೆಯ ಕೋಷ್ಟಕಗಳನ್ನು ಮೊದಲು ಸೇರಿಕೊಳ್ಳುವ ಪ್ರಶ್ನೆಯನ್ನು ಬರೆಯಲು ಡೆವಲಪರ್‌ಗೆ ಆಗಾಗ್ಗೆ ಸುಲಭವಾಗುತ್ತದೆ ಮತ್ತು ನಂತರ ಈ ಸಂಪೂರ್ಣ ಸೆಟ್‌ನಿಂದ ಕೇವಲ ಒಂದು ದಾಖಲೆ ಮಾತ್ರ ಉಳಿದಿದೆ. ಆದರೆ ಡೆವಲಪರ್‌ಗೆ ಸುಲಭ ಎಂದರೆ ಡೇಟಾಬೇಸ್‌ಗೆ ಹೆಚ್ಚು ಪರಿಣಾಮಕಾರಿ ಎಂದಲ್ಲ.
ನಮ್ಮ ಸಂದರ್ಭದಲ್ಲಿ ಕೇವಲ 3 ಕೋಷ್ಟಕಗಳು ಇದ್ದವು - ಮತ್ತು ಪರಿಣಾಮ ಏನು ...

"ಡಾಕ್ಯುಮೆಂಟ್ ಪ್ರಕಾರ" ಕೋಷ್ಟಕದೊಂದಿಗಿನ ಸಂಪರ್ಕವನ್ನು ಮೊದಲು ತೊಡೆದುಹಾಕೋಣ ಮತ್ತು ಅದೇ ಸಮಯದಲ್ಲಿ ಡೇಟಾಬೇಸ್ಗೆ ತಿಳಿಸಿ ನಮ್ಮ ಪ್ರಕಾರದ ದಾಖಲೆ ಅನನ್ಯವಾಗಿದೆ (ಇದು ನಮಗೆ ತಿಳಿದಿದೆ, ಆದರೆ ಶೆಡ್ಯೂಲರ್‌ಗೆ ಇನ್ನೂ ತಿಳಿದಿಲ್ಲ):

WITH T AS (
  SELECT
    "@ТипДокумента"
  FROM
    "ТипДокумента"
  WHERE
    "ТипДокумента" = 'ПланРабот'
  LIMIT 1
)
...
WHERE
  d."ТипДокумента" = (TABLE T)
...

ಹೌದು, ಟೇಬಲ್/CTE ಒಂದೇ ದಾಖಲೆಯ ಒಂದೇ ಕ್ಷೇತ್ರವನ್ನು ಹೊಂದಿದ್ದರೆ, ನಂತರ PG ಯಲ್ಲಿ ನೀವು ಈ ರೀತಿ ಬರೆಯಬಹುದು, ಬದಲಿಗೆ

d."ТипДокумента" = (SELECT "@ТипДокумента" FROM T LIMIT 1)

PostgreSQL ಪ್ರಶ್ನೆಗಳಲ್ಲಿ ಸೋಮಾರಿಯಾದ ಮೌಲ್ಯಮಾಪನ

BitmapOr vs UNION

ಕೆಲವು ಸಂದರ್ಭಗಳಲ್ಲಿ, ಬಿಟ್ಮ್ಯಾಪ್ ಹೀಪ್ ಸ್ಕ್ಯಾನ್ ನಮಗೆ ಬಹಳಷ್ಟು ವೆಚ್ಚವಾಗುತ್ತದೆ - ಉದಾಹರಣೆಗೆ, ನಮ್ಮ ಪರಿಸ್ಥಿತಿಯಲ್ಲಿ, ಸಾಕಷ್ಟು ದಾಖಲೆಗಳು ಅಗತ್ಯವಾದ ಸ್ಥಿತಿಯನ್ನು ಪೂರೈಸಿದಾಗ. ಏಕೆಂದರೆ ನಾವು ಅದನ್ನು ಪಡೆದುಕೊಂಡಿದ್ದೇವೆ ಅಥವಾ ಸ್ಥಿತಿಯನ್ನು BitmapOr ಆಗಿ ಪರಿವರ್ತಿಸಲಾಗಿದೆ- ಯೋಜನೆಯಲ್ಲಿ ಕಾರ್ಯಾಚರಣೆ.
ಮೂಲ ಸಮಸ್ಯೆಗೆ ಹಿಂತಿರುಗಿ ನೋಡೋಣ - ನಾವು ಅನುಗುಣವಾದ ದಾಖಲೆಯನ್ನು ಕಂಡುಹಿಡಿಯಬೇಕು ಯಾರಾದರೂ ಷರತ್ತುಗಳಿಂದ - ಅಂದರೆ, ಎರಡೂ ಷರತ್ತುಗಳ ಅಡಿಯಲ್ಲಿ ಎಲ್ಲಾ 59K ದಾಖಲೆಗಳನ್ನು ಹುಡುಕುವ ಅಗತ್ಯವಿಲ್ಲ. ಒಂದು ಸ್ಥಿತಿಯನ್ನು ಕೆಲಸ ಮಾಡಲು ಒಂದು ಮಾರ್ಗವಿದೆ, ಮತ್ತು ಮೊದಲನೆಯದರಲ್ಲಿ ಏನೂ ಸಿಗದಿದ್ದಾಗ ಮಾತ್ರ ಎರಡನೆಯದಕ್ಕೆ ಹೋಗಿ. ಕೆಳಗಿನ ವಿನ್ಯಾಸವು ನಮಗೆ ಸಹಾಯ ಮಾಡುತ್ತದೆ:

(
  SELECT
    ...
  LIMIT 1
)
UNION ALL
(
  SELECT
    ...
  LIMIT 1
)
LIMIT 1

"ಬಾಹ್ಯ" ಮಿತಿ 1 ಮೊದಲ ದಾಖಲೆ ಕಂಡುಬಂದಾಗ ಹುಡುಕಾಟವು ಕೊನೆಗೊಳ್ಳುತ್ತದೆ ಎಂದು ಖಚಿತಪಡಿಸುತ್ತದೆ. ಮತ್ತು ಇದು ಈಗಾಗಲೇ ಮೊದಲ ಬ್ಲಾಕ್ನಲ್ಲಿ ಕಂಡುಬಂದರೆ, ಎರಡನೇ ಬ್ಲಾಕ್ ಅನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸಲಾಗುವುದಿಲ್ಲ (ಎಂದಿಗೂ ಕಾರ್ಯಗತಗೊಳಿಸಲಾಗಿಲ್ಲ ಸಂಬಂಧಿಸಿದಂತೆ).

"ಕೇಸ್ ಅಡಿಯಲ್ಲಿ ಕಷ್ಟಕರ ಪರಿಸ್ಥಿತಿಗಳನ್ನು ಮರೆಮಾಡುವುದು"

ಮೂಲ ಪ್ರಶ್ನೆಯಲ್ಲಿ ಅತ್ಯಂತ ಅನನುಕೂಲವಾದ ಕ್ಷಣವಿದೆ - ಸಂಬಂಧಿತ ಟೇಬಲ್ "ಡಾಕ್ಯುಮೆಂಟ್ ಎಕ್ಸ್ಟೆನ್ಶನ್" ವಿರುದ್ಧ ಸ್ಥಿತಿಯನ್ನು ಪರಿಶೀಲಿಸಲಾಗುತ್ತಿದೆ. ಅಭಿವ್ಯಕ್ತಿಯಲ್ಲಿನ ಇತರ ಪರಿಸ್ಥಿತಿಗಳ ಸತ್ಯವನ್ನು ಲೆಕ್ಕಿಸದೆ (ಉದಾಹರಣೆಗೆ, d.“ಅಳಿಸಲಾಗಿದೆ” ನಿಜವಲ್ಲ), ಈ ಸಂಪರ್ಕವನ್ನು ಯಾವಾಗಲೂ ಕಾರ್ಯಗತಗೊಳಿಸಲಾಗುತ್ತದೆ ಮತ್ತು "ವೆಚ್ಚದ ಸಂಪನ್ಮೂಲಗಳು". ಅವುಗಳಲ್ಲಿ ಹೆಚ್ಚು ಅಥವಾ ಕಡಿಮೆ ಖರ್ಚು ಮಾಡಲಾಗುವುದು - ಈ ಮೇಜಿನ ಗಾತ್ರವನ್ನು ಅವಲಂಬಿಸಿರುತ್ತದೆ.
ಆದರೆ ನೀವು ಪ್ರಶ್ನೆಯನ್ನು ಮಾರ್ಪಡಿಸಬಹುದು ಇದರಿಂದ ಸಂಬಂಧಿತ ದಾಖಲೆಯ ಹುಡುಕಾಟವು ನಿಜವಾಗಿಯೂ ಅಗತ್ಯವಿದ್ದಾಗ ಮಾತ್ರ ಸಂಭವಿಸುತ್ತದೆ:

SELECT
  ...
FROM
  "Документ" d
WHERE
  ... /*index cond*/ AND
  CASE
    WHEN "$Черновик" IS NULL AND "Удален" IS NOT TRUE THEN (
      SELECT
        "Состояние"[1] IS TRUE
      FROM
        "ДокументРасширение"
      WHERE
        "@Документ" = d."@Документ"
    )
  END

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

ನನ್ನ ಕೊನೆಯ ಹೆಸರು "ಒಟ್ಟು"

ಮೇಲೆ ವಿವರಿಸಿದ ಎಲ್ಲಾ ಯಂತ್ರಶಾಸ್ತ್ರಗಳೊಂದಿಗೆ ನಾವು ಫಲಿತಾಂಶದ ಪ್ರಶ್ನೆಯನ್ನು ಸಂಗ್ರಹಿಸುತ್ತೇವೆ:

WITH T AS (
  SELECT
    "@ТипДокумента"
  FROM
    "ТипДокумента"
  WHERE
    "ТипДокумента" = 'ПланРабот'
)
  (
    SELECT
      TRUE
    FROM
      "Документ" d
    WHERE
      ("Лицо3", "ТипДокумента") = (19091, (TABLE T)) AND
      CASE
        WHEN "$Черновик" IS NULL AND "Удален" IS NOT TRUE THEN (
          SELECT
            "Состояние"[1] IS TRUE
          FROM
            "ДокументРасширение"
          WHERE
            "@Документ" = d."@Документ"
        )
      END
    LIMIT 1
  )
UNION ALL
  (
    SELECT
      TRUE
    FROM
      "Документ" d
    WHERE
      ("ТипДокумента", "Сотрудник") = ((TABLE T), 19091) AND
      CASE
        WHEN "$Черновик" IS NULL AND "Удален" IS NOT TRUE THEN (
          SELECT
            "Состояние"[1] IS TRUE
          FROM
            "ДокументРасширение"
          WHERE
            "@Документ" = d."@Документ"
        )
      END
    LIMIT 1
  )
LIMIT 1;

ಸೂಚಿಕೆಗಳನ್ನು ಸರಿಹೊಂದಿಸುವುದು

UNION ಉಪಬ್ಲಾಕ್‌ಗಳಲ್ಲಿನ ಸೂಚ್ಯಂಕ ಸ್ಥಿತಿಗಳು ಸ್ವಲ್ಪ ವಿಭಿನ್ನವಾಗಿವೆ ಎಂದು ತರಬೇತಿ ಪಡೆದ ಕಣ್ಣು ಗಮನಿಸಿದೆ - ಏಕೆಂದರೆ ನಾವು ಈಗಾಗಲೇ ಮೇಜಿನ ಮೇಲೆ ಸೂಕ್ತವಾದ ಸೂಚ್ಯಂಕಗಳನ್ನು ಹೊಂದಿದ್ದೇವೆ. ಮತ್ತು ಅವರು ಅಸ್ತಿತ್ವದಲ್ಲಿಲ್ಲದಿದ್ದರೆ, ಅದನ್ನು ರಚಿಸುವುದು ಯೋಗ್ಯವಾಗಿದೆ: ಡಾಕ್ಯುಮೆಂಟ್(ವ್ಯಕ್ತಿ3, ಡಾಕ್ಯುಮೆಂಟ್ ಪ್ರಕಾರ) и ಡಾಕ್ಯುಮೆಂಟ್ (ಡಾಕ್ಯುಮೆಂಟ್ ಪ್ರಕಾರ, ಉದ್ಯೋಗಿ).
ROW ಪರಿಸ್ಥಿತಿಗಳಲ್ಲಿ ಕ್ಷೇತ್ರಗಳ ಕ್ರಮದ ಬಗ್ಗೆಯೋಜಕರ ದೃಷ್ಟಿಕೋನದಿಂದ, ಸಹಜವಾಗಿ, ನೀವು ಬರೆಯಬಹುದು (A, B) = (constA, constB)ಮತ್ತು (B, A) = (constB, constA). ಆದರೆ ರೆಕಾರ್ಡಿಂಗ್ ಮಾಡುವಾಗ ಸೂಚ್ಯಂಕದಲ್ಲಿನ ಕ್ಷೇತ್ರಗಳ ಕ್ರಮದಲ್ಲಿ, ಅಂತಹ ವಿನಂತಿಯು ನಂತರ ಡೀಬಗ್ ಮಾಡಲು ಹೆಚ್ಚು ಅನುಕೂಲಕರವಾಗಿದೆ.
ಯೋಜನೆಯಲ್ಲಿ ಏನಿದೆ?
PostgreSQL ಆಂಟಿಪ್ಯಾಟರ್ನ್‌ಗಳು: ಹಾನಿಕಾರಕ ಸೇರ್ಪಡೆಗಳು ಮತ್ತು ORಗಳು
[explain.tensor.ru ನೋಡಿ]

ದುರದೃಷ್ಟವಶಾತ್, ನಾವು ದುರದೃಷ್ಟವಂತರು ಮತ್ತು ಮೊದಲ UNION ಬ್ಲಾಕ್‌ನಲ್ಲಿ ಏನೂ ಕಂಡುಬಂದಿಲ್ಲ, ಆದ್ದರಿಂದ ಎರಡನೆಯದನ್ನು ಇನ್ನೂ ಕಾರ್ಯಗತಗೊಳಿಸಲಾಗಿದೆ. ಆದರೆ ಹಾಗಿದ್ದರೂ - ಮಾತ್ರ 0.037ms ಮತ್ತು 11 ಬಫರ್‌ಗಳು!
ನಾವು ವಿನಂತಿಯನ್ನು ವೇಗಗೊಳಿಸಿದ್ದೇವೆ ಮತ್ತು ಮೆಮೊರಿಯಲ್ಲಿ ಡೇಟಾ ಪಂಪ್ ಮಾಡುವುದನ್ನು ಕಡಿಮೆಗೊಳಿಸಿದ್ದೇವೆ ಹಲವಾರು ಸಾವಿರ ಬಾರಿ, ಸರಳವಾದ ತಂತ್ರಗಳನ್ನು ಬಳಸುವುದು - ಸ್ವಲ್ಪ ಕಾಪಿ-ಪೇಸ್ಟ್ನೊಂದಿಗೆ ಉತ್ತಮ ಫಲಿತಾಂಶ. 🙂

ಮೂಲ: www.habr.com

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