Bữa tiệc vui vẻ hay đôi dòng kỷ niệm khi làm quen với việc phân vùng trong PostgreSQL10

Lời nói đầu hoặc ý tưởng chia phần ra đời như thế nào

Câu chuyện bắt đầu từ đây: Bạn có nhớ mọi chuyện đã bắt đầu như thế nào không? Mọi thứ đều như vậy lần đầu tiên và lần nữa. Sau khi gần như tất cả các nguồn lực để tối ưu hóa yêu cầu đã cạn kiệt vào thời điểm đó, câu hỏi đặt ra - tiếp theo là gì? Đây là cách nảy sinh ý tưởng phân vùng.

Bữa tiệc vui vẻ hay đôi dòng kỷ niệm khi làm quen với việc phân vùng trong PostgreSQL10

Sự lạc đề trữ tình:
Chính xác là 'vào thời điểm đó', bởi vì hóa ra là có những dự trữ tối ưu hóa chưa được khai thác. Cảm ơn ừm và Habru!

Vì vậy, làm cách nào khác để bạn có thể làm cho khách hàng hài lòng, đồng thời cải thiện kỹ năng của chính mình?

Để đơn giản hóa mọi thứ nhất có thể, thì chỉ có hai cách để cải thiện triệt để điều gì đó về hiệu suất của cơ sở dữ liệu:
1) Đường dẫn mở rộng - chúng tôi tăng tài nguyên, thay đổi cấu hình;
2) Đường dẫn chuyên sâu - tối ưu hóa truy vấn

Vì, tôi nhắc lại, vào thời điểm đó không còn rõ cần thay đổi gì nữa trong yêu cầu tăng tốc nên đường dẫn đã được chọn - thay đổi thiết kế bảng.

Vì vậy, câu hỏi chính được đặt ra: chúng ta sẽ thay đổi điều gì và như thế nào?

Điều kiện ban đầu

Đầu tiên, có ERD này (được thể hiện theo cách đơn giản hóa có điều kiện):
Bữa tiệc vui vẻ hay đôi dòng kỷ niệm khi làm quen với việc phân vùng trong PostgreSQL10
Các tính năng chính:

  1. mối quan hệ nhiều-nhiều
  2. bảng đã có khóa phân vùng tiềm năng

Yêu cầu ban đầu:

SELECT
            p."PARAMETER_ID" as  parameter_id,
            pc."PC_NAME" AS pc_name,
            pc."CUSTOMER_PARTNUMBER" AS customer_partnumber,
            w."LASERMARK" AS lasermark,
            w."LOTID" AS lotid,
            w."REPORTED_VALUE" AS reported_value,
            w."LOWER_SPEC_LIMIT" AS lower_spec_limit,
            w."UPPER_SPEC_LIMIT" AS upper_spec_limit,
            p."TYPE_CALCUL" AS type_calcul,
            s."SHIPMENT_NAME" AS shipment_name,
            s."SHIPMENT_DATE" AS shipment_date,
            extract(year from s."SHIPMENT_DATE") AS year,
            extract(month from s."SHIPMENT_DATE") as month,
            s."REPORT_NAME" AS report_name,
            p."SPARAM_NAME" AS SPARAM_name,
            p."CUSTOMERPARAM_NAME" AS customerparam_name
        FROM data w INNER JOIN shipment s ON s."SHIPMENT_ID" = w."SHIPMENT_ID"
             INNER JOIN parameters p ON p."PARAMETER_ID" = w."PARAMETER_ID"
             INNER JOIN shipment_pc sp ON s."SHIPMENT_ID" = sp."SHIPMENT_ID"
             INNER JOIN pc pc ON pc."PC_ID" = sp."PC_ID"
             INNER JOIN ( SELECT w2."LASERMARK" , MAX(s2."SHIPMENT_DATE") AS "SHIPMENT_DATE"
                          FROM shipment s2 INNER JOIN data w2 ON s2."SHIPMENT_ID" = w2."SHIPMENT_ID" 
                          GROUP BY w2."LASERMARK"
                         ) md ON md."SHIPMENT_DATE" = s."SHIPMENT_DATE" AND md."LASERMARK" = w."LASERMARK"
        WHERE 
             s."SHIPMENT_DATE" >= '2018-07-01' AND s."SHIPMENT_DATE" <= '2018-09-30' ;

Kết quả thực hiện trên cơ sở dữ liệu thử nghiệm:
Phí Tổn : 502 997.55
Thời gian thực hiện: 505 giây.

Chúng ta thấy gì? Một yêu cầu thường xuyên, dựa trên một lát thời gian.
Chúng ta hãy đưa ra giả định logic đơn giản nhất: nếu có một mẫu lát cắt thời gian, liệu nó có giúp ích cho chúng ta không? Đúng vậy - phân vùng.

Những gì để phần?

Thoạt nhìn, sự lựa chọn rất rõ ràng - phân vùng khai báo của bảng “lô hàng” bằng khóa “SHIPMENT_DATE” (nhảy quá xa về phía trước - cuối cùng hóa ra có một chút sai sót trong quá trình sản xuất).

Làm thế nào để phân vùng?

Câu hỏi này cũng không quá khó. May mắn thay, trong PostgreSQL 10 hiện đã có cơ chế phân vùng do con người thực hiện.
Vì vậy:

  1. Lưu kết xuất của bảng nguồn - pg_dump nguồn_table
  2. Xóa bảng gốc - thả bảng source_table
  3. Tạo bảng cha có phân vùng phạm vi - tạo bảng source_table
  4. Tạo phần - tạo bảng source_table, tạo chỉ mục
  5. Nhập kết xuất được tạo ở bước 1 - pg_restore

Kịch bản phân vùng

Để đơn giản và thuận tiện, các bước 2,3,4 đã được gộp lại thành một tập lệnh.

Vì vậy:
Lưu kết xuất của bảng nguồn

pg_dump postgres --file=/dump/shipment.dmp --format=c --table=shipment --verbose > /dump/shipment.log 2>&1

Xóa bảng nguồn + Tạo bảng cha có phân vùng theo phạm vi + Tạo phân vùng

--create_partition_shipment.sql
do language plpgsql $$
declare 
rec_shipment_date RECORD ;
partition_name varchar;
index_name varchar;
current_year varchar ;
current_month varchar ;
begin_year varchar ;
begin_month varchar ;
next_year varchar ;
next_month varchar ;
first_flag boolean ;
i integer ;
begin
  RAISE NOTICE 'CREATE TEMPORARY TABLE FOR SHIPMENT_DATE';
  CREATE TEMP TABLE tmp_shipment_date as select distinct "SHIPMENT_DATE" from shipment order by "SHIPMENT_DATE" ;

  RAISE NOTICE 'DROP TABLE shipment';
  drop table shipment cascade ;
  
  CREATE TABLE public.shipment
  (
    "SHIPMENT_ID" integer NOT NULL DEFAULT nextval('shipment_shipment_id_seq'::regclass),
    "SHIPMENT_NAME" character varying(30) COLLATE pg_catalog."default",
    "SHIPMENT_DATE" timestamp without time zone,
    "REPORT_NAME" character varying(40) COLLATE pg_catalog."default"
  )
  PARTITION BY RANGE ("SHIPMENT_DATE")
  WITH (
      OIDS = FALSE
  )
  TABLESPACE pg_default;

  RAISE NOTICE 'CREATE PARTITIONS FOR TABLE shipment';

  current_year:='0';
  current_month:='0';

  begin_year := '0' ;
  begin_month := '0'  ;
  next_year := '0' ;
  next_month := '0'  ;

  FOR rec_shipment_date IN SELECT * FROM tmp_shipment_date LOOP
      
      RAISE NOTICE 'SHIPMENT_DATE=%',rec_shipment_date."SHIPMENT_DATE";
      
      current_year := date_part('year' ,rec_shipment_date."SHIPMENT_DATE");
      current_month := date_part('month' ,rec_shipment_date."SHIPMENT_DATE") ; 

      IF to_number(current_month,'99') < 10 THEN
        current_month := '0'||current_month ; 
      END IF ;

      --Init borders
      IF   begin_year = '0' THEN
       first_flag := true ; --first time flag
       begin_year := current_year ;
       begin_month := current_month ;   
   
        IF current_month = '12' THEN
          next_year := date_part('year' ,rec_shipment_date."SHIPMENT_DATE" + interval '1 year') ;
        ELSE
          next_year := current_year ;
        END IF;
     
       next_month := date_part('month' ,rec_shipment_date."SHIPMENT_DATE" + interval '1 month') ;

      END IF;

      -- Check current date into borders NOT for First time
      IF to_date( current_year||'.'||current_month, 'YYYY.MM') >= to_date( begin_year||'.'||begin_month, 'YYYY.MM') AND 
         to_date( current_year||'.'||current_month, 'YYYY.MM') < to_date( next_year||'.'||next_month, 'YYYY.MM') AND 
         NOT first_flag 
      THEN
         CONTINUE ; 
      ELSE
       --NEW borders only for second and after time 
       begin_year := current_year ;
       begin_month := current_month ;   
   
        IF current_month = '12' THEN
          next_year := date_part('year' ,rec_shipment_date."SHIPMENT_DATE" + interval '1 year') ;
        ELSE
          next_year := current_year ;
        END IF;
     
       next_month := date_part('month' ,rec_shipment_date."SHIPMENT_DATE" + interval '1 month') ;

      END IF;      

      partition_name := 'shipment_shipment_date_'||begin_year||'-'||begin_month||'-01-'|| next_year||'-'||next_month||'-01'  ;
 
     EXECUTE format('CREATE TABLE ' || quote_ident(partition_name) || ' PARTITION OF shipment FOR VALUES FROM ( %L ) TO ( %L )  ' , current_year||'-'||current_month||'-01' , next_year||'-'||next_month||'-01'  ) ; 

      index_name := partition_name||'_shipment_id_idx';
      RAISE NOTICE 'INDEX NAME =%',index_name;
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("SHIPMENT_ID") TABLESPACE pg_default ' ) ; 

      --Drop first time flag
      first_flag := false ;
   
  END LOOP;

end
$$;

Nhập khẩu bãi chứa

pg_restore -d postgres --data-only --format=c --table=shipment --verbose  shipment.dmp > /tmp/data_dump/shipment_restore.log 2>&1

Kiểm tra kết quả phân vùng

Kết quả là chúng ta có gì? Toàn bộ nội dung của kế hoạch thực hiện rất dài và nhàm chán, vì vậy bạn hoàn toàn có thể giới hạn bản thân ở những con số cuối cùng.

Đã

Chi phí: 502 997.55
Thời gian thực hiện: 505 giây.

Đã trở thành

Chi phí: 77 872.36
Thời gian thực hiện: 79 giây.

Một kết quả khá tốt. Giảm chi phí và thời gian thực hiện. Vì vậy, việc sử dụng phân vùng mang lại hiệu quả như mong đợi và nói chung là không có gì đáng ngạc nhiên.

Làm cho khách hàng hài lòng

Kết quả kiểm tra đã được trình bày cho khách hàng để xem xét. Và sau khi xem xét, họ đã nhận được một phán quyết có phần bất ngờ: “Tuyệt vời, hãy phân vùng bảng “dữ liệu”.

Có, nhưng chúng tôi đã kiểm tra một bảng “lô hàng” hoàn toàn khác; bảng “dữ liệu” không có trường “SHIPMENT_DATE”.

Không có vấn đề, thêm, thay đổi. Điều chính là khách hàng hài lòng với kết quả, chi tiết thực hiện không đặc biệt quan trọng.

Phân vùng bảng chính “dữ liệu”

Nói chung, không có khó khăn đặc biệt nào phát sinh. Mặc dù vậy, tất nhiên, thuật toán phân vùng đã thay đổi phần nào.

Thêm cột “SHIPMENT_DATA” vào bảng “data”

psql -h хост -U база -d юзер
=> ALTER TABLE data ADD COLUMN "SHIPMENT_DATE" timestamp without time zone ;

Điền các giá trị của cột “SHIPMENT_DATA” trong bảng “data” với các giá trị của cột cùng tên từ bảng “lô hàng”

-----------------------------
--update_data.sql
--updating for altered table "data" to values of "shipment_data" from the table "shipment"
--version 1.0
do language plpgsql $$
declare 
rec_shipment_data RECORD ;
shipment_date timestamp without time zone ; 
row_count integer ;
total_rows integer ;
begin

  select count(*) into total_rows from shipment ; 
  RAISE NOTICE 'Total %',total_rows;
  row_count:= 0 ;

  FOR rec_shipment_data IN SELECT * FROM shipment LOOP

   update data set "SHIPMENT_DATE" = rec_shipment_data."SHIPMENT_DATE" where "SHIPMENT_ID" = rec_shipment_data."SHIPMENT_ID";
   
   row_count:=  row_count +1 ;
   RAISE NOTICE 'row count = % , from %',row_count,total_rows;
  END LOOP;

end
$$;

Lưu kết xuất của bảng “dữ liệu”

pg_dump postgres --file=/dump/data.dmp --format=c --table=data --verbose > /dump/data.log 2>&1</source

Tạo lại bảng phân vùng "dữ liệu"

--create_partition_data.sql
--create partitions for the table "wafer data" by range column "shipment_data" with one month duration
--version 1.0
do language plpgsql $$
declare 
rec_shipment_date RECORD ;
partition_name varchar;
index_name varchar;
current_year varchar ;
current_month varchar ;
begin_year varchar ;
begin_month varchar ;
next_year varchar ;
next_month varchar ;
first_flag boolean ;
i integer ;

begin

  RAISE NOTICE 'CREATE TEMPORARY TABLE FOR SHIPMENT_DATE';
  CREATE TEMP TABLE tmp_shipment_date as select distinct "SHIPMENT_DATE" from shipment order by "SHIPMENT_DATE" ;


  RAISE NOTICE 'DROP TABLE data';
  drop table data cascade ;


  RAISE NOTICE 'CREATE PARTITIONED TABLE data';
  
  CREATE TABLE public.data
  (
    "RUN_ID" integer,
    "LASERMARK" character varying(20) COLLATE pg_catalog."default" NOT NULL,
    "LOTID" character varying(80) COLLATE pg_catalog."default",
    "SHIPMENT_ID" integer NOT NULL,
    "PARAMETER_ID" integer NOT NULL,
    "INTERNAL_VALUE" character varying(75) COLLATE pg_catalog."default",
    "REPORTED_VALUE" character varying(75) COLLATE pg_catalog."default",
    "LOWER_SPEC_LIMIT" numeric,
    "UPPER_SPEC_LIMIT" numeric , 
    "SHIPMENT_DATE" timestamp without time zone
  )
  PARTITION BY RANGE ("SHIPMENT_DATE")
  WITH (
    OIDS = FALSE
  )
  TABLESPACE pg_default ;


  RAISE NOTICE 'CREATE PARTITIONS FOR TABLE data';

  current_year:='0';
  current_month:='0';

  begin_year := '0' ;
  begin_month := '0'  ;
  next_year := '0' ;
  next_month := '0'  ;
  i := 1;

  FOR rec_shipment_date IN SELECT * FROM tmp_shipment_date LOOP
      
      RAISE NOTICE 'SHIPMENT_DATE=%',rec_shipment_date."SHIPMENT_DATE";
      
      current_year := date_part('year' ,rec_shipment_date."SHIPMENT_DATE");
      current_month := date_part('month' ,rec_shipment_date."SHIPMENT_DATE") ; 

      --Init borders
      IF   begin_year = '0' THEN
       RAISE NOTICE '***Init borders';
       first_flag := true ; --first time flag
       begin_year := current_year ;
       begin_month := current_month ;   
   
        IF current_month = '12' THEN
          next_year := date_part('year' ,rec_shipment_date."SHIPMENT_DATE" + interval '1 year') ;
        ELSE
          next_year := current_year ;
        END IF;
     
       next_month := date_part('month' ,rec_shipment_date."SHIPMENT_DATE" + interval '1 month') ;

      END IF;

--      RAISE NOTICE 'current_year=% , current_month=% ',current_year,current_month;
--      RAISE NOTICE 'begin_year=% , begin_month=% ',begin_year,begin_month;
--      RAISE NOTICE 'next_year=% , next_month=% ',next_year,next_month;

      -- Check current date into borders NOT for First time

      RAISE NOTICE 'Current data = %',to_char( to_date( current_year||'.'||current_month, 'YYYY.MM'), 'YYYY.MM');
      RAISE NOTICE 'Begin data = %',to_char( to_date( begin_year||'.'||begin_month, 'YYYY.MM'), 'YYYY.MM');
      RAISE NOTICE 'Next data = %',to_char( to_date( next_year||'.'||next_month, 'YYYY.MM'), 'YYYY.MM');

      IF to_date( current_year||'.'||current_month, 'YYYY.MM') >= to_date( begin_year||'.'||begin_month, 'YYYY.MM') AND 
         to_date( current_year||'.'||current_month, 'YYYY.MM') < to_date( next_year||'.'||next_month, 'YYYY.MM') AND 
         NOT first_flag 
      THEN
         RAISE NOTICE '***CONTINUE';
         CONTINUE ; 
      ELSE
       --NEW borders only for second and after time 
       RAISE NOTICE '***NEW BORDERS';
       begin_year := current_year ;
       begin_month := current_month ;   
   
        IF current_month = '12' THEN
          next_year := date_part('year' ,rec_shipment_date."SHIPMENT_DATE" + interval '1 year') ;
        ELSE
          next_year := current_year ;
        END IF;
     
       next_month := date_part('month' ,rec_shipment_date."SHIPMENT_DATE" + interval '1 month') ;


      END IF;      

      IF to_number(current_month,'99') < 10 THEN
        current_month := '0'||current_month ; 
      END IF ;

      IF to_number(begin_month,'99') < 10 THEN
        begin_month := '0'||begin_month ; 
      END IF ;

      IF to_number(next_month,'99') < 10 THEN
        next_month := '0'||next_month ; 
      END IF ;

      RAISE NOTICE 'current_year=% , current_month=% ',current_year,current_month;
      RAISE NOTICE 'begin_year=% , begin_month=% ',begin_year,begin_month;
      RAISE NOTICE 'next_year=% , next_month=% ',next_year,next_month;

      partition_name := 'data_'||begin_year||begin_month||'01_'||next_year||next_month||'01'  ;

      RAISE NOTICE 'PARTITION NUMBER % , TABLE NAME =%',i , partition_name;
      
      EXECUTE format('CREATE TABLE ' || quote_ident(partition_name) || ' PARTITION OF data FOR VALUES FROM ( %L ) TO ( %L )  ' , begin_year||'-'||begin_month||'-01' , next_year||'-'||next_month||'-01'  ) ; 

      index_name := partition_name||'_shipment_id_parameter_id_idx';
      RAISE NOTICE 'INDEX NAME =%',index_name;
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("SHIPMENT_ID", "PARAMETER_ID") TABLESPACE pg_default ' ) ; 

      index_name := partition_name||'_lasermark_idx';
      RAISE NOTICE 'INDEX NAME =%',index_name;
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("LASERMARK" COLLATE pg_catalog."default") TABLESPACE pg_default ' ) ; 

      index_name := partition_name||'_shipment_id_idx';
      RAISE NOTICE 'INDEX NAME =%',index_name;
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("SHIPMENT_ID") TABLESPACE pg_default ' ) ; 

      index_name := partition_name||'_parameter_id_idx';
      RAISE NOTICE 'INDEX NAME =%',index_name;
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("PARAMETER_ID") TABLESPACE pg_default ' ) ; 

      index_name := partition_name||'_shipment_date_idx';
      RAISE NOTICE 'INDEX NAME =%',index_name;
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("SHIPMENT_DATE") TABLESPACE pg_default ' ) ; 

      --Drop first time flag
      first_flag := false ;

  END LOOP;
end
$$;

Tải kết xuất được tạo ở bước 3.

pg_restore -h хост -юзер -d база --data-only --format=c --table=data --verbose  data.dmp > data_restore.log 2>&1

Tạo một phần riêng cho dữ liệu cũ

---------------------------------------------------
--create_partition_for_old_dates.sql
--create partitions for keeping old dates 
--version 1.0
do language plpgsql $$
declare 
rec_shipment_date RECORD ;
partition_name varchar;
index_name varchar;

begin

      SELECT min("SHIPMENT_DATE") AS min_date INTO rec_shipment_date from data ;

      RAISE NOTICE 'Old date is %',rec_shipment_date.min_date ;

      partition_name := 'data_old_dates'  ;

      RAISE NOTICE 'PARTITION NAME IS %',partition_name;

      EXECUTE format('CREATE TABLE ' || quote_ident(partition_name) || ' PARTITION OF data FOR VALUES FROM ( %L ) TO ( %L )  ' , '1900-01-01' , 
              to_char( rec_shipment_date.min_date,'YYYY')||'-'||to_char(rec_shipment_date.min_date,'MM')||'-01'  ) ; 

      index_name := partition_name||'_shipment_id_parameter_id_idx';
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("SHIPMENT_ID", "PARAMETER_ID") TABLESPACE pg_default ' ) ; 

      index_name := partition_name||'_lasermark_idx';
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("LASERMARK" COLLATE pg_catalog."default") TABLESPACE pg_default ' ) ; 

      index_name := partition_name||'_shipment_id_idx';
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("SHIPMENT_ID") TABLESPACE pg_default ' ) ; 

      index_name := partition_name||'_parameter_id_idx';
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("PARAMETER_ID") TABLESPACE pg_default ' ) ; 

      index_name := partition_name||'_shipment_date_idx';
      EXECUTE format('CREATE INDEX ' || quote_ident(index_name) || ' ON '|| quote_ident(partition_name) ||' USING btree ("SHIPMENT_DATE") TABLESPACE pg_default ' ) ; 

end
$$;

Kết quả cuối cùng:

Đã
Chi phí: 502 997.55
Thời gian thực hiện: 505 giây.

Đã trở thành
Chi phí: 68 533.70
Thời gian thực hiện: 69 giây

Xứng đáng, khá xứng đáng. Và xét rằng trong quá trình thực hiện, chúng tôi đã ít nhiều thành thạo cơ chế phân vùng trong PostgreSQL 10 - một kết quả tuyệt vời.

Lạc đề trữ tình

Có thể làm tốt hơn nữa không - CÓ, BẠN CÓ THỂ!Để làm được điều này, bạn cần sử dụng CHẾ ĐỘ XEM VẬT LIỆU.
TẠO CHẾ ĐỘ XEM VẬT LIỆU LASERMARK_VIEW

CREATE MATERIALIZED VIEW LASERMARK_VIEW 
AS
SELECT w."LASERMARK" , MAX(s."SHIPMENT_DATE") AS "SHIPMENT_DATE"
FROM shipment s INNER JOIN data w ON s."SHIPMENT_ID" = w."SHIPMENT_ID" 
GROUP BY w."LASERMARK" ;

CREATE INDEX lasermark_vw_shipment_date_ind on lasermark_view USING btree ("SHIPMENT_DATE") TABLESPACE pg_default;
analyze lasermark_view ;

Một lần nữa chúng tôi viết lại yêu cầu:
Truy vấn bằng cách sử dụng chế độ xem cụ thể hóa

SELECT
            p."PARAMETER_ID" as  parameter_id,
            pc."PC_NAME" AS pc_name,
            pc."CUSTOMER_PARTNUMBER" AS customer_partnumber,
            w."LASERMARK" AS lasermark,
            w."LOTID" AS lotid,
            w."REPORTED_VALUE" AS reported_value,
            w."LOWER_SPEC_LIMIT" AS lower_spec_limit,
            w."UPPER_SPEC_LIMIT" AS upper_spec_limit,
            p."TYPE_CALCUL" AS type_calcul,
            s."SHIPMENT_NAME" AS shipment_name,
            s."SHIPMENT_DATE" AS shipment_date,
            extract(year from s."SHIPMENT_DATE") AS year,
            extract(month from s."SHIPMENT_DATE") as month,
            s."REPORT_NAME" AS report_name,
            p."STC_NAME" AS STC_name,
            p."CUSTOMERPARAM_NAME" AS customerparam_name
        FROM data w INNER JOIN shipment s ON s."SHIPMENT_ID" = w."SHIPMENT_ID"
             INNER JOIN parameters p ON p."PARAMETER_ID" = w."PARAMETER_ID"
             INNER JOIN shipment_pc sp ON s."SHIPMENT_ID" = sp."SHIPMENT_ID"
             INNER JOIN pc pc ON pc."PC_ID" = sp."PC_ID"
             INNER JOIN LASERMARK_VIEW md ON md."SHIPMENT_DATE" = s."SHIPMENT_DATE" AND md."LASERMARK" = w."LASERMARK"
        WHERE 
              s."SHIPMENT_DATE" >= '2018-07-01' AND s."SHIPMENT_DATE" <= '2018-09-30';

Và chúng ta nhận được một kết quả khác:
Đã
Chi phí: 502 997.55
Thời gian thực hiện: 505 giây

Đã trở thành
Chi phí: 42 481.16
Thời gian thực hiện: 43 giây.

Tất nhiên, mặc dù kết quả đầy hứa hẹn như vậy là sai lầm; các ý tưởng cần phải được làm mới. Vì vậy tổng thời gian nhận dữ liệu sẽ không giúp ích được gì nhiều. Nhưng như một thử nghiệm, nó khá thú vị.

Trên thực tế, hóa ra là vậy, cảm ơn một lần nữa ừm và Habru!- Truy vấn có thể được cải thiện hơn nữa.

bạt

Vì vậy, khách hàng hài lòng. VÀ cần lợi dụng hoàn cảnh.

Nhiệm vụ mới: Bạn có thể nghĩ ra điều gì để đào sâu và mở rộng?

Và sau đó tôi nhớ ra - các bạn, chúng tôi không có hệ thống giám sát cơ sở dữ liệu PostgreSQL của mình.

Thực tế là vẫn có một số hoạt động giám sát dưới dạng Cloud Watch trên AWS. Nhưng lợi ích của việc giám sát này đối với DBA là gì? Nói chung, thực tế là không có.

Nếu có cơ hội làm được điều gì đó hữu ích và thú vị cho bản thân thì bạn không thể không tận dụng cơ hội này...


Bữa tiệc vui vẻ hay đôi dòng kỷ niệm khi làm quen với việc phân vùng trong PostgreSQL10

Đây là cách chúng ta đi đến phần thú vị nhất:

Ngày 3 tháng 2018 năm XNUMX.
Đưa ra quyết định bắt đầu nghiên cứu các khả năng sẵn có để theo dõi hiệu suất của các truy vấn PostgreSQL.

Nhưng đó là một câu chuyện hoàn toàn khác.

Còn tiếp…

Nguồn: www.habr.com

Thêm một lời nhận xét