ನನ್ನ ಕೆಲಸದ ಕಾರಣದಿಂದಾಗಿ, ಡೆವಲಪರ್ ವಿನಂತಿಯನ್ನು ಬರೆದಾಗ ಮತ್ತು ಯೋಚಿಸಿದಾಗ ನಾನು ಸಂದರ್ಭಗಳನ್ನು ಎದುರಿಸಬೇಕಾಗುತ್ತದೆ "ಬೇಸ್ ಸ್ಮಾರ್ಟ್ ಆಗಿದೆ, ಅದು ಎಲ್ಲವನ್ನೂ ಸ್ವತಃ ನಿಭಾಯಿಸಬಲ್ಲದು!«
ಕೆಲವು ಸಂದರ್ಭಗಳಲ್ಲಿ (ಭಾಗಶಃ ಡೇಟಾಬೇಸ್ನ ಸಾಮರ್ಥ್ಯಗಳ ಅಜ್ಞಾನದಿಂದ, ಭಾಗಶಃ ಅಕಾಲಿಕ ಆಪ್ಟಿಮೈಸೇಶನ್ಗಳಿಂದ), ಈ ವಿಧಾನವು "ಫ್ರಾಂಕೆನ್ಸ್ಟೈನ್ಗಳ" ನೋಟಕ್ಕೆ ಕಾರಣವಾಗುತ್ತದೆ.
ಮೊದಲಿಗೆ, ಅಂತಹ ವಿನಂತಿಯ ಉದಾಹರಣೆಯನ್ನು ನಾನು ನೀಡುತ್ತೇನೆ:
-- для каждой ключевой пары находим ассоциированные значения полей
WITH RECURSIVE cte_bind AS (
SELECT DISTINCT ON (key_a, key_b)
key_a a
, key_b b
, fld1 bind_fld1
, fld2 bind_fld2
FROM
tbl
)
-- находим min/max значений для каждого первого ключа
, cte_max AS (
SELECT
a
, max(bind_fld1) bind_fld1
, min(bind_fld2) bind_fld2
FROM
cte_bind
GROUP BY
a
)
-- связываем по первому ключу ключевые пары и min/max-значения
, cte_a_bind AS (
SELECT
cte_bind.a
, cte_bind.b
, cte_max.bind_fld1
, cte_max.bind_fld2
FROM
cte_bind
INNER JOIN
cte_max
ON cte_max.a = cte_bind.a
)
SELECT * FROM cte_a_bind;
ವಿನಂತಿಯ ಗುಣಮಟ್ಟವನ್ನು ಗಣನೀಯವಾಗಿ ಮೌಲ್ಯಮಾಪನ ಮಾಡಲು, ಕೆಲವು ಅನಿಯಂತ್ರಿತ ಡೇಟಾ ಸೆಟ್ ಅನ್ನು ರಚಿಸೋಣ:
CREATE TABLE tbl AS
SELECT
(random() * 1000)::integer key_a
, (random() * 1000)::integer key_b
, (random() * 10000)::integer fld1
, (random() * 10000)::integer fld2
FROM
generate_series(1, 10000);
CREATE INDEX ON tbl(key_a, key_b);
ಎಂದು ತಿರುಗುತ್ತದೆ ಡೇಟಾವನ್ನು ಓದುವುದು ಕಾಲು ಭಾಗಕ್ಕಿಂತ ಕಡಿಮೆ ಸಮಯವನ್ನು ತೆಗೆದುಕೊಳ್ಳುತ್ತದೆ ಪ್ರಶ್ನೆ ಕಾರ್ಯಗತಗೊಳಿಸುವಿಕೆ:
ಅದನ್ನು ತುಂಡು ತುಂಡಾಗಿ ತೆಗೆಯುವುದು
ವಿನಂತಿಯನ್ನು ಹತ್ತಿರದಿಂದ ನೋಡೋಣ ಮತ್ತು ಗೊಂದಲಕ್ಕೊಳಗಾಗೋಣ:
- ಯಾವುದೇ ಪುನರಾವರ್ತಿತ CTE ಗಳಿಲ್ಲದಿದ್ದರೆ ಇಲ್ಲಿ ಏಕೆ ರಿಕರ್ಸಿವ್ ಆಗಿದೆ?
- ಹೇಗಾದರೂ ಮೂಲ ಮಾದರಿಯೊಂದಿಗೆ ಕಟ್ಟಿದ್ದರೆ ಪ್ರತ್ಯೇಕ CTE ನಲ್ಲಿ ನಿಮಿಷ/ಗರಿಷ್ಠ ಮೌಲ್ಯಗಳನ್ನು ಏಕೆ ಗುಂಪು ಮಾಡಬೇಕು?
+ 25% ಸಮಯ - ಹಿಂದಿನ CTE ಅನ್ನು ಪುನರಾವರ್ತಿಸಲು ಕೊನೆಯಲ್ಲಿ ಬೇಷರತ್ತಾದ 'SELECT * FROM' ಅನ್ನು ಏಕೆ ಬಳಸಬೇಕು?
+ 14% ಸಮಯ
ಈ ಸಂದರ್ಭದಲ್ಲಿ, ಹ್ಯಾಶ್ ಜಾಯ್ನ್ ಅನ್ನು ಸಂಪರ್ಕಕ್ಕಾಗಿ ಆಯ್ಕೆ ಮಾಡಿರುವುದು ನಮ್ಮ ಅದೃಷ್ಟ, ಮತ್ತು ನೆಸ್ಟೆಡ್ ಲೂಪ್ ಅಲ್ಲ, ಏಕೆಂದರೆ ಆಗ ನಾವು ಕೇವಲ ಒಂದು CTE ಸ್ಕ್ಯಾನ್ ಪಾಸ್ ಅನ್ನು ಸ್ವೀಕರಿಸುವುದಿಲ್ಲ, ಆದರೆ 10K!
CTE ಸ್ಕ್ಯಾನ್ ಬಗ್ಗೆ ಸ್ವಲ್ಪಇಲ್ಲಿ ನಾವು ಅದನ್ನು ನೆನಪಿನಲ್ಲಿಟ್ಟುಕೊಳ್ಳಬೇಕು CTE ಸ್ಕ್ಯಾನ್ Seq ಸ್ಕ್ಯಾನ್ ಅನ್ನು ಹೋಲುತ್ತದೆ - ಅಂದರೆ, ಯಾವುದೇ ಇಂಡೆಕ್ಸಿಂಗ್ ಇಲ್ಲ, ಆದರೆ ಸಂಪೂರ್ಣ ಹುಡುಕಾಟ ಮಾತ್ರ ಅಗತ್ಯವಿರುತ್ತದೆ 10K x 0.3ms = 3000ms cte_max ಮೂಲಕ ಚಕ್ರಗಳಿಗೆ ಅಥವಾ 1K x 1.5ms = 1500ms cte_bind ಮೂಲಕ ಲೂಪ್ ಮಾಡುವಾಗ!
ವಾಸ್ತವವಾಗಿ, ನೀವು ಪರಿಣಾಮವಾಗಿ ಏನನ್ನು ಪಡೆಯಲು ಬಯಸುತ್ತೀರಿ? ಹೌದು, ಸಾಮಾನ್ಯವಾಗಿ ಇದು "ಮೂರು-ಅಂತಸ್ತಿನ" ಪ್ರಶ್ನೆಗಳನ್ನು ವಿಶ್ಲೇಷಿಸುವ 5 ನೇ ನಿಮಿಷದಲ್ಲಿ ಎಲ್ಲೋ ಬರುವ ಪ್ರಶ್ನೆಯಾಗಿದೆ.
ನಾವು ಪ್ರತಿ ಅನನ್ಯ ಕೀ ಜೋಡಿಯನ್ನು ಔಟ್ಪುಟ್ ಮಾಡಲು ಬಯಸಿದ್ದೇವೆ ಕೀ_ಎ ಮೂಲಕ ಗುಂಪಿನಿಂದ ನಿಮಿಷ/ಗರಿಷ್ಠ.
ಆದ್ದರಿಂದ ಇದನ್ನು ಬಳಸೋಣ
SELECT DISTINCT ON(key_a, key_b)
key_a a
, key_b b
, max(fld1) OVER(w) bind_fld1
, min(fld2) OVER(w) bind_fld2
FROM
tbl
WINDOW
w AS (PARTITION BY key_a);
ಎರಡೂ ಆಯ್ಕೆಗಳಲ್ಲಿ ಡೇಟಾವನ್ನು ಓದುವುದು ಸರಿಸುಮಾರು 4-5ms ತೆಗೆದುಕೊಳ್ಳುತ್ತದೆ, ನಂತರ ನಮ್ಮ ಎಲ್ಲಾ ಸಮಯ ಲಾಭ -32% - ಇದು ಅದರ ಶುದ್ಧ ರೂಪದಲ್ಲಿದೆ ಮೂಲ CPU ನಿಂದ ಲೋಡ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ, ಅಂತಹ ವಿನಂತಿಯನ್ನು ಸಾಕಷ್ಟು ಬಾರಿ ಕಾರ್ಯಗತಗೊಳಿಸಿದರೆ.
ಸಾಮಾನ್ಯವಾಗಿ, ನೀವು ಬೇಸ್ ಅನ್ನು "ಸುತ್ತಿನದನ್ನು ಒಯ್ಯಲು, ಚೌಕವನ್ನು ಸುತ್ತಲು" ಒತ್ತಾಯಿಸಬಾರದು.
ಮೂಲ: www.habr.com