PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Tối ưu hóa thao tác CHÈN / CẬP NHẬT / XÓA

Định nghĩa bảng đã sửa đổi

Nếu bạn thực sự cần các cột đó phải NOT NULL và bạn thực sự cần chuỗi 'default' làm mặc định cho engine_slug , Tôi khuyên bạn nên giới thiệu các giá trị mặc định của cột:

COLUMN           |          TYPE           |      Modifiers
-----------------+-------------------------+---------------------
 id              | INTEGER                 | NOT NULL DEFAULT ... 
 engine_slug     | CHARACTER VARYING(200)  | NOT NULL DEFAULT 'default'
 content_type_id | INTEGER                 | NOT NULL
 object_id       | text                    | NOT NULL
 object_id_int   | INTEGER                 |
 title           | CHARACTER VARYING(1000) | NOT NULL
 description     | text                    | NOT NULL DEFAULT ''
 content         | text                    | NOT NULL
 url             | CHARACTER VARYING(1000) | NOT NULL DEFAULT ''
 meta_encoded    | text                    | NOT NULL DEFAULT '{}'
 search_tsv      | tsvector                | NOT NULL
 ...

Câu lệnh DDL sẽ là:

ALTER TABLE watson_searchentry ALTER COLUMN  engine_slug DEFAULT 'default';

Vv.

Sau đó, bạn không phải chèn các giá trị đó theo cách thủ công mỗi lần.

Ngoài ra:object_id text NOT NULL, object_id_int INTEGER ? Thật ki quặc. Tôi đoán bạn có lý do của mình ...

Tôi sẽ xử lý yêu cầu cập nhật của bạn:

Tất nhiên, bạn phải thêm một DUY NHẤT ràng buộc để thực thi các yêu cầu của bạn:

ALTER TABLE watson_searchentry
ADD CONSTRAINT ws_uni UNIQUE (content_type_id, object_id_int)

Chỉ mục đi kèm sẽ được sử dụng. Bằng truy vấn này cho người mới bắt đầu.

BTW, tôi hầu như không bao giờ sử dụng varchar(n) trong Postgres. Chỉ cần text . Đây là một lý do.

Truy vấn với CTE sửa đổi dữ liệu

Điều này có thể được viết lại dưới dạng một truy vấn SQL duy nhất với các biểu thức bảng phổ biến sửa đổi dữ liệu, còn được gọi là CTE "có thể ghi". Yêu cầu Postgres 9.1 trở lên.
Ngoài ra, truy vấn này chỉ xóa những gì phải xóa và cập nhật những gì có thể cập nhật.

WITH  ctyp AS (
   SELECT id AS content_type_id
   FROM   django_content_type
   WHERE  app_label = 'web'
   AND    model = 'member'
   )
, sel AS (
   SELECT ctyp.content_type_id
         ,m.id       AS object_id_int
         ,m.id::text AS object_id       -- explicit cast!
         ,m.name     AS title
         ,concat_ws(' ', u.email,m.normalized_name,c.name) AS content
         -- other columns have column default now.
   FROM   web_user    u
   JOIN   web_member  m  ON m.user_id = u.id
   JOIN   web_country c  ON c.id = m.country_id
   CROSS  JOIN ctyp
   WHERE  u.is_active
   )
, del AS (     -- only if you want to del all other entries of same type
   DELETE FROM watson_searchentry w
   USING  ctyp
   WHERE  w.content_type_id = ctyp.content_type_id
   AND    NOT EXISTS (
      SELECT 1
      FROM   sel
      WHERE  sel.object_id_int = w.object_id_int
      )
   )
, up AS (      -- update existing rows
   UPDATE watson_searchentry 
   SET    object_id = s.object_id
         ,title     = s.title
         ,content   = s.content
   FROM   sel s
   WHERE  w.content_type_id = s.content_type_id
   AND    w.object_id_int   = s.object_id_int
   )
               -- insert new rows
INSERT  INTO watson_searchentry (
        content_type_id, object_id_int, object_id, title, content)
SELECT  sel.*  -- safe to use, because col list is defined accordingly above
FROM    sel
LEFT    JOIN watson_searchentry w1 USING (content_type_id, object_id_int)
WHERE   w1.content_type_id IS NULL;
  • Truy vấn con trên django_content_type luôn trả về một giá trị duy nhất? Nếu không, CROSS JOIN có thể gây ra sự cố.

  • CTE sel đầu tiên tập hợp các hàng được chèn. Lưu ý cách tôi chọn tên cột phù hợp để đơn giản hóa mọi thứ.

  • Trong CTE del Tôi tránh xóa các hàng có thể được cập nhật.

  • Trong CTE up những hàng đó được cập nhật thay thế.

  • Do đó, tôi tránh chèn các hàng chưa bị xóa trước đó trong INSERT cuối cùng .

Có thể dễ dàng được gói vào một hàm SQL hoặc PL / pgSQL để sử dụng nhiều lần.

Không an toàn khi sử dụng đồng thời nhiều. Tốt hơn nhiều so với chức năng bạn đã có, nhưng vẫn không mạnh mẽ 100% so với chức năng ghi đồng thời. Nhưng đó không phải là vấn đề theo thông tin cập nhật của bạn.

Việc thay thế CẬP NHẬT bằng XÓA và CHÈN có thể đắt hơn hoặc không đắt hơn rất nhiều. Nội bộ mỗi UPDATE luôn dẫn đến một phiên bản hàng mới, do MVCC mô hình .

Tốc độ đầu tiên

Nếu bạn không thực sự quan tâm đến việc bảo tồn các hàng cũ, cách tiếp cận đơn giản hơn của bạn có thể nhanh hơn:Xóa mọi thứ và chèn các hàng mới. Ngoài ra, gói thành một hàm plpgsql giúp tiết kiệm một chút chi phí lập kế hoạch. Về cơ bản, chức năng của bạn, với một vài đơn giản hóa nhỏ và tuân theo các giá trị mặc định được thêm ở trên:

CREATE OR REPLACE FUNCTION update_member_search_index()
  RETURNS VOID AS
$func$
DECLARE
   _ctype_id int := (
      SELECT id
      FROM   django_content_type
      WHERE  app_label='web'
      AND    model = 'member'
      );  -- you can assign at declaration time. saves another statement
BEGIN
   DELETE FROM watson_searchentry
   WHERE content_type_id = _ctype_id;

   INSERT INTO watson_searchentry
         (content_type_id, object_id, object_id_int, title, content)
   SELECT _ctype_id, m.id, m.id::int,m.name
         ,u.email || ' ' || m.normalized_name || ' ' || c.name
   FROM   web_member  m
   JOIN   web_user    u USING (user_id)
   JOIN   web_country c ON c.id = m.country_id
   WHERE  u.is_active;
END
$func$ LANGUAGE plpgsql;

Tôi thậm chí không sử dụng concat_ws() :Nó an toàn chống lại NULL và đơn giản hóa mã, nhưng chậm hơn một chút so với nối đơn giản.

Ngoài ra:

Sẽ nhanh hơn nếu kết hợp logic vào chức năng này - nếu đây là lần duy nhất cần kích hoạt. Mặt khác, nó có lẽ không đáng để ồn ào.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. cách thực hiện tìm kiếm lượt like trong postgresql và node js

  2. Nhận dữ liệu 12 tháng qua từ Db với năm trong Postgres

  3. Chế độ postgresql H2 dường như không hoạt động với tôi

  4. Hiệu suất thứ tự mệnh đề WHERE và JOIN

  5. SQL động (EXECUTE) làm điều kiện cho câu lệnh IF