PK เชตเช—เชฐเชจเชพ เชŸเซ‡เชฌเชฒเชฎเชพเช‚เชฅเซ€ เช•เซเชฒเซ‹เชจ เชฐเซ‡เช•เซ‹เชฐเซเชกเซเชธ เชธเชพเชซ เช•เชฐเชตเซเช‚

เชเชตเซ€ เชชเชฐเชฟเชธเซเชฅเชฟเชคเชฟเช“ เช›เซ‡ เชœเซเชฏเชพเชฐเซ‡ เชชเซเชฐเชพเชฅเชฎเชฟเช• เช•เซ€ เชตเช—เชฐเชจเชพ เชŸเซ‡เชฌเชฒ เชชเชฐ เช…เชฅเชตเชพ เช…เชฎเซเช• เช…เชจเซเชฏ เช…เชจเชจเซเชฏ เช…เชจเซเช•เซเชฐเชฎเชฃเชฟเช•เชพ, เชฆเซ‡เช–เชฐเซ‡เช–เชจเซ‡ เช•เชพเชฐเชฃเซ‡, เชชเชนเซ‡เชฒเชพเชฅเซ€ เช…เชธเซเชคเชฟเชคเซเชตเชฎเชพเช‚ เช›เซ‡ เชคเซ‡เชตเชพ เชฐเซ‡เช•เซ‹เชฐเซเชกเซเชธเชจเชพ เชธเช‚เชชเซ‚เชฐเซเชฃ เช•เซเชฒเซ‹เชจเซเชธเชจเซ‹ เชธเชฎเชพเชตเซ‡เชถ เชฅเชพเชฏ เช›เซ‡.

PK เชตเช—เชฐเชจเชพ เชŸเซ‡เชฌเชฒเชฎเชพเช‚เชฅเซ€ เช•เซเชฒเซ‹เชจ เชฐเซ‡เช•เซ‹เชฐเซเชกเซเชธ เชธเชพเชซ เช•เชฐเชตเซเช‚

เช‰เชฆเชพเชนเชฐเชฃ เชคเชฐเซ€เช•เซ‡, เช•เชพเชฒเช•เซเชฐเชฎเชฟเช• เชฎเซ‡เชŸเซเชฐเชฟเช•เชจเชพ เชฎเซ‚เชฒเซเชฏเซ‹ เชชเซ‹เชธเซเชŸเช—เซเชฐเซ‡เชเชธเช•เซเชฏเซเชเชฒเชฎเชพเช‚ เช•เซ‹เชชเซ€ เชธเซเชŸเซเชฐเซ€เชฎเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เชจเซ‡ เชฒเช–เชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡, เช…เชจเซ‡ เชชเช›เซ€ เช…เชšเชพเชจเช• เชจเชฟเชทเซเชซเชณเชคเชพ เช†เชตเซ‡ เช›เซ‡, เช…เชจเซ‡ เชธเช‚เชชเซ‚เชฐเซเชฃเชชเชฃเซ‡ เชธเชฎเชพเชจ เชกเซ‡เชŸเชพเชจเซ‹ เชญเชพเช— เชซเชฐเซ€เชฅเซ€ เช†เชตเซ‡ เช›เซ‡.

เชฌเชฟเชจเชœเชฐเซ‚เชฐเซ€ เช•เซเชฒเซ‹เชจเซเชธเชจเชพ เชกเซ‡เชŸเชพเชฌเซ‡เชเชฅเซ€ เช•เซ‡เชตเซ€ เชฐเซ€เชคเซ‡ เช›เซเชŸเช•เชพเชฐเซ‹ เชฎเซ‡เชณเชตเชตเซ‹?

เชœเซเชฏเชพเชฐเซ‡ เชชเซ€เช•เซ‡ เชฎเชฆเชฆเช—เชพเชฐ เชจเชฅเซ€

เช†เชตเซ€ เชชเชฐเชฟเชธเซเชฅเชฟเชคเชฟเชจเซ‡ เชชเซเชฐเชฅเชฎ เชธเซเชฅเชพเชจเซ‡ เชฌเชจเชคเชพ เช…เชŸเช•เชพเชตเชตเชพเชจเซ‹ เชธเซŒเชฅเซ€ เชธเชนเซ‡เชฒเซ‹ เชฐเชธเซเชคเซ‹ เช›เซ‡. เช‰เชฆเชพเชนเชฐเชฃ เชคเชฐเซ€เช•เซ‡, เชชเซเชฐเชพเชฅเชฎเชฟเช• เช•เซ€ เชฐเซ‹เชฒ เช•เชฐเซ‹. เชชเชฐเช‚เชคเซ เชธเช‚เช—เซเชฐเชนเชฟเชค เชกเซ‡เชŸเชพเชจเชพ เชตเซ‹เชฒเซเชฏเซเชฎเชฎเชพเช‚ เชตเชงเชพเชฐเซ‹ เช•เชฐเซเชฏเชพ เชตเชฟเชจเชพ เช† เชนเช‚เชฎเซ‡เชถเชพ เชถเช•เซเชฏ เชจเชฅเซ€.

เช‰เชฆเชพเชนเชฐเชฃ เชคเชฐเซ€เช•เซ‡, เชœเซ‹ เชธเซเชฐเซ‹เชค เชธเชฟเชธเซเชŸเชฎเชจเซ€ เชšเซ‹เช•เชธเชพเชˆ เชกเซ‡เชŸเชพเชฌเซ‡เชเชฎเชพเช‚เชจเชพ เช•เซเชทเซ‡เชคเซเชฐเชจเซ€ เชšเซ‹เช•เชธเชพเชˆ เช•เชฐเชคเชพ เชตเชงเชพเชฐเซ‡ เช›เซ‡:

metric   | ts                  | data
--------------------------------------------------
cpu.busy | 2019-12-20 00:00:00 | {"value" : 12.34}
cpu.busy | 2019-12-20 00:00:01 | {"value" : 10}
cpu.busy | 2019-12-20 00:00:01 | {"value" : 11.2}
cpu.busy | 2019-12-20 00:00:03 | {"value" : 15.7}

เชถเซเช‚ เชคเชฎเซ‡ เชจเซ‹เช‚เชงเซเชฏเซเช‚? 00:00:02 เชจเซ‡ เชฌเชฆเชฒเซ‡ เช•เชพเช‰เชจเซเชŸเชกเชพเช‰เชจ เชกเซ‡เชŸเชพเชฌเซ‡เชเชฎเชพเช‚ ts เชธเชพเชฅเซ‡ เชเช• เชธเซ‡เช•เชจเซเชก เช…เช—เชพเช‰ เชฐเซ‡เช•เซ‹เชฐเซเชก เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเซเชฏเซเช‚ เชนเชคเซเช‚, เชชเชฐเช‚เชคเซ เชเชชเซเชฒเชฟเช•เซ‡เชถเชจเชจเชพ เชฆเซƒเชทเซเชŸเชฟเช•เซ‹เชฃเชฅเซ€ เชคเซ‡ เชคเชฆเซเชฆเชจ เชฎเชพเชจเซเชฏ เชฐเชนเซเชฏเซเช‚ (เช›เซ‡เชตเชŸเซ‡, เชกเซ‡เชŸเชพ เชฎเซ‚เชฒเซเชฏเซ‹ เช…เชฒเช— เช›เซ‡!).

เช…เชฒเชฌเชคเซเชค เชคเชฎเซ‡ เชคเซ‡ เช•เชฐเซ€ เชถเช•เซ‹ เช›เซ‹ PK(เชฎเซ‡เชŸเซเชฐเชฟเช•, ts) - เชชเชฐเช‚เชคเซ เชชเช›เซ€ เช…เชฎเชจเซ‡ เชฎเชพเชจเซเชฏ เชกเซ‡เชŸเชพ เชฎเชพเชŸเซ‡ เชจเชฟเชตเซ‡เชถ เชคเช•เชฐเชพเชฐ เชฎเชณเชถเซ‡.

เช•เชฐเซ€ เชถเช•เชตเซ PK(เชฎเซ‡เชŸเซเชฐเชฟเช•, ts, เชกเซ‡เชŸเชพ) - เชชเชฐเช‚เชคเซ เช† เชคเซ‡เชจเชพ เชตเซ‹เชฒเซเชฏเซเชฎเชฎเชพเช‚ เชฎเซ‹เชŸเชพ เชชเซเชฐเชฎเชพเชฃเชฎเชพเช‚ เชตเชงเชพเชฐเซ‹ เช•เชฐเชถเซ‡, เชœเซ‡เชจเซ‹ เช†เชชเชฃเซ‡ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เชถเซเช‚ เชจเชนเซ€เช‚.

เชคเซ‡เชฅเซ€, เชธเซŒเชฅเซ€ เชธเชพเชšเซ‹ เชตเชฟเช•เชฒเซเชช เช เช›เซ‡ เช•เซ‡ เชจเชฟเชฏเชฎเชฟเชค เชฌเชฟเชจ-เชฏเซเชจเชฟเช• เช‡เชจเซเชกเซ‡เช•เซเชธ เชฌเชจเชพเชตเชตเซ‹ (เชฎเซ‡เชŸเซเชฐเชฟเช•, ts) เช…เชจเซ‡ เชนเช•เซ€เช•เชค เชชเช›เซ€ เชœเซ‹ เชธเชฎเชธเซเชฏเชพเช“ เชŠเชญเซ€ เชฅเชพเชฏ เชคเซ‹ เชคเซ‡เชจเซ‹ เชธเชพเชฎเชจเซ‹ เช•เชฐเซ‹.

"เช•เซเชฒเซ‹เชจเชฟเช• เชฏเซเชฆเซเชง เชถเชฐเซ‚ เชฅเชฏเซเช‚ เช›เซ‡"

เช•เซ‹เชˆ เชชเซเชฐเช•เชพเชฐเชจเซ‹ เช…เช•เชธเซเชฎเชพเชค เชฅเชฏเซ‹, เช…เชจเซ‡ เชนเชตเซ‡ เช†เชชเชฃเซ‡ เชŸเซ‡เชฌเชฒเชฎเชพเช‚เชฅเซ€ เช•เซเชฒเซ‹เชจ เชฐเซ‡เช•เซ‹เชฐเซเชกเซเชธเชจเซ‹ เชจเชพเชถ เช•เชฐเชตเซ‹ เชชเชกเชถเซ‡.

PK เชตเช—เชฐเชจเชพ เชŸเซ‡เชฌเชฒเชฎเชพเช‚เชฅเซ€ เช•เซเชฒเซ‹เชจ เชฐเซ‡เช•เซ‹เชฐเซเชกเซเชธ เชธเชพเชซ เช•เชฐเชตเซเช‚

เชšเชพเชฒเซ‹ เชฎเซ‚เชณ เชกเซ‡เชŸเชพเชจเซเช‚ เชฎเซ‹เชกเซ‡เชฒ เช•เชฐเซ€เช:

CREATE TABLE tbl(k text, v integer);

INSERT INTO tbl
VALUES
  ('a', 1)
, ('a', 3)
, ('b', 2)
, ('b', 2) -- oops!
, ('c', 3)
, ('c', 3) -- oops!!
, ('c', 3) -- oops!!
, ('d', 4)
, ('e', 5)
;

เช…เชนเซ€เช‚ เช…เชฎเชพเชฐเซ‹ เชนเชพเชฅ เชคเซเชฐเชฃ เชตเช–เชค เชงเซเชฐเซ‚เชœเซเชฏเซ‹, Ctrl+V เช…เชŸเช•เซ€ เช—เชฏเซ‹, เช…เชจเซ‡ เชนเชตเซ‡...

เชธเซŒเชชเซเชฐเชฅเชฎ, เชšเชพเชฒเซ‹ เชธเชฎเชœเซ€เช เช•เซ‡ เช†เชชเชฃเซเช‚ เชŸเซ‡เชฌเชฒ เช˜เชฃเซเช‚ เชฎเซ‹เชŸเซเช‚ เชนเซ‹เชˆ เชถเช•เซ‡ เช›เซ‡, เชคเซ‡เชฅเซ€ เช†เชชเชฃเซ‡ เชฌเชงเชพ เช•เซเชฒเซ‹เชจเซเชธ เชถเซ‹เชงเซ€ เช•เชพเชขเซเชฏเชพ เชชเช›เซ€, เชกเชฟเชฒเซ€เชŸ เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡ เช†เชชเชฃเชจเซ‡ เชถเชพเชฌเซเชฆเชฟเช• เชฐเซ€เชคเซ‡ "เช†เชชเชฃเซ€ เช†เช‚เช—เชณเซ€เชจเซ‡ เชฅเซ‚เช‚เช•เชตเซเช‚" เชธเชฒเชพเชน เช†เชชเชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡. เชšเซ‹เช•เซเช•เชธ เชฐเซ‡เช•เซ‹เชฐเซเชกเชจเซ‡ เชซเชฐเซ€เชฅเซ€ เชถเซ‹เชงเซเชฏเชพ เชตเชฟเชจเชพ.

เช…เชจเซ‡ เช†เชตเซ€ เชเช• เชฐเซ€เชค เช›เซ‡ - เช† ctid เชฆเซเชตเชพเชฐเชพ เชธเช‚เชฌเซ‹เชงเชจ, เชšเซ‹เช•เซเช•เชธ เชฐเซ‡เช•เซ‹เชฐเซเชกเชจเซเช‚ เชญเซŒเชคเชฟเช• เช“เชณเช–เช•เชฐเซเชคเชพ.

เชเชŸเชฒเซ‡ เช•เซ‡, เชธเซŒ เชชเซเชฐเชฅเชฎ, เช†เชชเชฃเซ‡ เช•เซ‹เชทเซเชŸเช• เชชเช‚เช•เซเชคเชฟเชจเซ€ เชธเช‚เชชเซ‚เชฐเซเชฃ เชธเชพเชฎเช—เซเชฐเซ€เชจเชพ เชธเช‚เชฆเชฐเซเชญเชฎเชพเช‚ เชฐเซ‡เช•เซ‹เชฐเซเชกเซเชธเชจเซ€ ctid เชเช•เชคเซเชฐเชฟเชค เช•เชฐเชตเชพเชจเซ€ เชœเชฐเซ‚เชฐ เช›เซ‡. เช†เช–เซ€ เชฒเชพเช‡เชจเชจเซ‡ เชŸเซ‡เช•เซเชธเซเชŸเชฎเชพเช‚ เช•เชพเชธเซเชŸ เช•เชฐเชตเชพเชจเซ‹ เชธเซŒเชฅเซ€ เชธเชฐเชณ เชตเชฟเช•เชฒเซเชช เช›เซ‡:

SELECT
  T::text
, array_agg(ctid) ctids
FROM
  tbl T
GROUP BY
  1;

t     | ctids
---------------------------------
(e,5) | {"(0,9)"}
(d,4) | {"(0,8)"}
(c,3) | {"(0,5)","(0,6)","(0,7)"}
(b,2) | {"(0,3)","(0,4)"}
(a,3) | {"(0,2)"}
(a,1) | {"(0,1)"}

เชถเซเช‚ เช•เชพเชธเซเชŸ เชจ เช•เชฐเชตเซเช‚ เชถเช•เซเชฏ เช›เซ‡?เชธเซˆเชฆเซเชงเชพเช‚เชคเชฟเช• เชฐเซ€เชคเซ‡, เชฎเซ‹เชŸเชพเชญเชพเช—เชจเชพ เช•เชฟเชธเซเชธเชพเช“เชฎเชพเช‚ เชคเซ‡ เชถเช•เซเชฏ เช›เซ‡. เชœเซเชฏเชพเช‚ เชธเซเชงเซ€ เชคเชฎเซ‡ เช† เช•เซ‹เชทเซเชŸเช•เชฎเชพเช‚ เชซเซ€เชฒเซเชกเซเชธเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเชตเชพเชจเซเช‚ เชถเชฐเซ‚ เช•เชฐเชถเซ‹ เชจเชนเซ€เช‚ เชธเชฎเชพเชจเชคเชพ เช“เชชเชฐเซ‡เชŸเชฐ เชตเช—เชฐเชจเชพ เชชเซเชฐเช•เชพเชฐเซ‹:

CREATE TABLE tbl(k text, v integer, x point);
SELECT
  array_agg(ctid) ctids
FROM
  tbl T
GROUP BY
  T;
-- ERROR:  could not identify an equality operator for type tbl

เชนเชพ, เช…เชฎเซ‡ เชคเชฐเชค เชœ เชœเซ‹เชˆ เชถเช•เซ€เช เช›เซ€เช เช•เซ‡ เชœเซ‹ เชเชฐเซ‡เชฎเชพเช‚ เชเช• เช•เชฐเชคเชพเช‚ เชตเชงเซ เชเชจเซเชŸเซเชฐเซ€ เชนเซ‹เชฏ, เชคเซ‹ เช† เชฌเชงเชพ เช•เซเชฒเซ‹เชจเซเชธ เช›เซ‡. เชšเชพเชฒเซ‹ เชคเซ‡เชฎเชจเซ‡ เช›เซ‹เชกเซ€เช:

SELECT
  unnest(ctids[2:])
FROM
  (
    SELECT
      array_agg(ctid) ctids
    FROM
      tbl T
    GROUP BY
      T::text
  ) T;

unnest
------
(0,6)
(0,7)
(0,4)

เชœเซ‡เช“ เชŸเซ‚เช‚เช•เซเช‚ เชฒเช–เชตเชพเชจเซเช‚ เชชเชธเช‚เชฆ เช•เชฐเซ‡ เช›เซ‡ เชคเซ‡เชฎเชจเชพ เชฎเชพเชŸเซ‡เชคเชฎเซ‡ เชคเซ‡เชจเซ‡ เช† เชฐเซ€เชคเซ‡ เชชเชฃ เชฒเช–เซ€ เชถเช•เซ‹ เช›เซ‹:

SELECT
  unnest((array_agg(ctid))[2:])
FROM
  tbl T
GROUP BY
  T::text;

เช•เซเชฐเชฎเชพเช‚เช•เชฟเชค เชธเซเชŸเซเชฐเชฟเช‚เช—เชจเซเช‚ เชฎเซ‚เชฒเซเชฏ เชชเซ‹เชคเซ‡ เชœ เช…เชฎเชจเซ‡ เชฐเชธเชชเซเชฐเชฆ เชจ เชนเซ‹เชตเชพเชฅเซ€, เช…เชฎเซ‡ เชคเซ‡เชจเซ‡ เชธเชฌเช•เซเชตเซ‡เชฐเซ€เชจเชพเช‚ เชชเชฐเชค เช•เชฐเซ‡เชฒเชพ เช•เซ‰เชฒเชฎเชฎเชพเช‚เชฅเซ€ เช–เชพเชฒเซ€ เชซเซ‡เช‚เช•เซ€ เชฆเซ€เชงเซเช‚ เช›เซ‡.

เชนเชœเซ€ เชฅเซ‹เชกเซเช‚เช• เช•เชฐเชตเชพเชจเซเช‚ เชฌเชพเช•เซ€ เช›เซ‡ - เช…เชฎเชจเซ‡ เชฎเชณเซ‡เชฒเชพ เชธเซ‡เชŸเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เชจเซ‡ DELETE เช•เชฐเซ‹:

DELETE FROM
  tbl
WHERE
  ctid = ANY(ARRAY(
    SELECT
      unnest(ctids[2:])
    FROM
      (
        SELECT
          array_agg(ctid) ctids
        FROM
          tbl T
        GROUP BY
          T::text
      ) T
  )::tid[]);

เชšเชพเชฒเซ‹ เช†เชชเชฃเซ€ เชœเชพเชคเชจเซ‡ เชคเชชเชพเชธเซ€เช:

PK เชตเช—เชฐเชจเชพ เชŸเซ‡เชฌเชฒเชฎเชพเช‚เชฅเซ€ เช•เซเชฒเซ‹เชจ เชฐเซ‡เช•เซ‹เชฐเซเชกเซเชธ เชธเชพเชซ เช•เชฐเชตเซเช‚
[explan.tensor.ru เชชเชฐ เชœเซเช“]

เชนเชพ, เชฌเชงเซเช‚ เชธเชพเชšเซเช‚ เช›เซ‡: เช…เชฎเชพเชฐเชพ 3 เชฐเซ‡เช•เซ‹เชฐเซเชก เช†เช–เชพ เชŸเซ‡เชฌเชฒเชจเชพ เชเช•เชฎเชพเชคเซเชฐ เชธเซ‡เช• เชธเซเช•เซ‡เชจ เชฎเชพเชŸเซ‡ เชชเชธเช‚เชฆ เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเซเชฏเชพ เชนเชคเชพ, เช…เชจเซ‡ เชกเชฟเชฒเซ€เชŸ เชจเซ‹เชกเชจเซ‹ เช‰เชชเชฏเซ‹เช— เชกเซ‡เชŸเชพ เชถเซ‹เชงเชตเชพ เชฎเชพเชŸเซ‡ เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเซเชฏเซ‹ เชนเชคเซ‹. เชŸเซ€เชก เชธเซเช•เซ‡เชจ เชธเชพเชฅเซ‡ เชธเชฟเช‚เช—เชฒ เชชเชพเชธ:

->  Tid Scan on tbl (actual time=0.050..0.051 rows=3 loops=1)
      TID Cond: (ctid = ANY ($0))

เชœเซ‹ เชคเชฎเซ‡ เช˜เชฃเชพ เชฌเชงเชพ เชฐเซ‡เช•เซ‹เชฐเซเชก เชธเชพเชซ เช•เชฐเซเชฏเชพ เชนเซ‹เชฏ, เชตเซ‡เช•เซเชฏเซเชฎ เชตเชฟเชถเซเชฒเซ‡เชทเชฃ เชšเชฒเชพเชตเชตเชพเชจเซเช‚ เชญเซ‚เชฒเชถเซ‹ เชจเชนเซ€เช‚.

เชšเชพเชฒเซ‹ เชฎเซ‹เชŸเชพ เชŸเซ‡เชฌเชฒ เชฎเชพเชŸเซ‡ เช…เชจเซ‡ เชฎเซ‹เชŸเซ€ เชธเช‚เช–เซเชฏเชพเชฎเชพเช‚ เชกเซเชชเซเชฒเชฟเช•เซ‡เชŸ เชธเชพเชฅเซ‡ เชคเชชเชพเชธ เช•เชฐเซ€เช:

TRUNCATE TABLE tbl;

INSERT INTO tbl
SELECT
  chr(ascii('a'::text) + (random() * 26)::integer) k -- a..z
, (random() * 100)::integer v -- 0..99
FROM
  generate_series(1, 10000) i;

PK เชตเช—เชฐเชจเชพ เชŸเซ‡เชฌเชฒเชฎเชพเช‚เชฅเซ€ เช•เซเชฒเซ‹เชจ เชฐเซ‡เช•เซ‹เชฐเซเชกเซเชธ เชธเชพเชซ เช•เชฐเชตเซเช‚
[explan.tensor.ru เชชเชฐ เชœเซเช“]

เชคเซ‡เชฅเซ€, เชชเชฆเซเชงเชคเชฟ เชธเชซเชณเชคเชพเชชเซ‚เชฐเซเชตเช• เช•เชพเชฐเซเชฏ เช•เชฐเซ‡ เช›เซ‡, เชชเชฐเช‚เชคเซ เชคเซ‡เชจเซ‹ เช‰เชชเชฏเซ‹เช— เชฅเซ‹เชกเซ€ เชธเชพเชตเชงเชพเชจเซ€ เชธเชพเชฅเซ‡ เชฅเชตเซ‹ เชœเซ‹เชˆเช. เช•เชพเชฐเชฃ เช•เซ‡ เชกเชฟเชฒเซ€เชŸ เชฅเชฏเซ‡เชฒ เชฆเชฐเซ‡เช• เชฐเซ‡เช•เซ‹เชฐเซเชก เชฎเชพเชŸเซ‡, เชเช• เชกเซ‡เชŸเชพ เชชเซ‡เชœ Tid Scan เชฎเชพเช‚ เชตเชพเช‚เชšเชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡ เช…เชจเซ‡ เชเช• Delete เชฎเชพเช‚.

เชธเซ‹เชฐเซเชธ: www.habr.com

เชเช• เชŸเชฟเชชเซเชชเชฃเซ€ เช‰เชฎเซ‡เชฐเซ‹