Khi nào sử dụng bảng kế thừa trong PostgreSQL?


84

Bạn nên sử dụng bảng kế thừa trong những trường hợp nào? Tôi đã cố gắng sử dụng chúng rất ngắn và tính kế thừa dường như không giống như trong thế giới OOP.

Tôi nghĩ nó hoạt động như thế này:

Bảng userscó tất cả các trường bắt buộc cho mọi cấp độ người dùng. Bàn thích moderators, admins, bloggers, vv nhưng các lĩnh vực đang không kiểm tra từ cha mẹ. Ví dụ userscó trường email và kế thừa bloggerscũng có trường này nhưng nó không phải là duy nhất cho cả hai usersbloggerscùng một lúc. I E. giống như tôi thêm trường email vào cả hai bảng.

Chỉ sử dụng tôi có thể nghĩ đến là lĩnh vực mà thường được sử dụng, như row_is_deleted , created_at , modified_at . Đây có phải là cách sử dụng duy nhất cho các bảng kế thừa?

Câu trả lời:


111

Có một số lý do chính cho việc sử dụng kế thừa bảng trong postgres.

Giả sử, chúng tôi có một số bảng cần thiết để thống kê, được tạo và điền vào mỗi tháng:

statistics
    - statistics_2010_04 (inherits statistics)
    - statistics_2010_05 (inherits statistics)

Trong mẫu này, chúng tôi có 2.000.000 hàng trong mỗi bảng. Mỗi bảng có ràng buộc KIỂM TRA để đảm bảo chỉ dữ liệu cho tháng phù hợp mới được lưu trữ trong đó.

Vậy điều gì làm cho tính năng kế thừa trở thành một tính năng thú vị - tại sao việc chia nhỏ dữ liệu lại thú vị?

  • HIỆU SUẤT: Khi chọn dữ liệu, chúng tôi CHỌN * TỪ số liệu thống kê TRONG ĐÓ ngày tháng GIỮA x và Y, và Postgres chỉ sử dụng các bảng, nơi nó có ý nghĩa. Ví dụ. CHỌN * TỪ thống kê ĐÂU ngày tháng GIỮA '2010-04-01' VÀ '2010-04-15' chỉ quét thống kê bảng_2010_04, tất cả các bảng khác sẽ không được chạm vào - nhanh!
  • Kích thước chỉ mục: Chúng tôi không có bảng chất béo lớn với chỉ số chất béo lớn vào ngày cột. Chúng tôi có các bảng nhỏ mỗi tháng, với các chỉ mục nhỏ - đọc nhanh hơn.
  • Bảo trì: Chúng tôi có thể chạy chân không đầy đủ, lập chỉ mục lại, cụm trên bảng mỗi tháng mà không cần khóa tất cả dữ liệu khác

Để sử dụng chính xác kế thừa bảng làm tăng hiệu suất, hãy xem hướng dẫn sử dụng postgresql. Bạn cần đặt ràng buộc KIỂM TRA trên mỗi bảng để cho cơ sở dữ liệu biết, dữ liệu của bạn sẽ được chia (phân vùng) trên khóa nào.

Tôi sử dụng nhiều kế thừa bảng, đặc biệt là khi nói đến lưu trữ dữ liệu nhật ký được nhóm theo tháng. Gợi ý: Nếu bạn lưu trữ dữ liệu sẽ không bao giờ thay đổi (dữ liệu nhật ký), hãy tạo hoặc lập chỉ mục với CREATE INDEX ON () WITH (fillfactor = 100); Điều này có nghĩa là không có dung lượng cho các bản cập nhật sẽ được dành riêng trong chỉ mục - chỉ mục nhỏ hơn trên đĩa.

CẬP NHẬT: mặc định của fillfactor là 100, từ http://www.postgresql.org/docs/9.1/static/sql-createtable.html :

Hệ số lấp đầy cho một bảng là tỷ lệ phần trăm từ 10 đến 100. 100 (đóng gói hoàn chỉnh) là mặc định


13
Một ví dụ khác partioning
Frank Heikens

4
Trong mục 1 của bạn, làm thế nào để Postgres hiểu bảng nào là cần thiết để tìm kiếm? Bạn chọn từ bảng chính và phạm vi ngày chỉ là một ví dụ thuận tiện về việc tách. Bảng cha không thể biết logic này. Hay tôi nhầm?
Alexander Palamarchuk

4
Thực hiện truy vấn trên bảng mẹ thực sự giống như thực hiện truy vấn trên UNION ALL trên mọi bảng con trên các hàng chung. Công cụ lập kế hoạch truy vấn biết các ràng buộc kiểm tra xác định từng phân vùng và miễn là chúng không chồng chéo các phân vùng thì sử dụng chúng để xác định rằng nó có thể bỏ qua việc kiểm tra các bảng mà CHECK cho biết không có hàng nào được trả về. Postgres tài liệu về vấn đề này
zxq9

@avesus heh ... Đoạn mã trên do chính nó lấy ra cũng đáng bị mỉa mai như vậy. Thông thường, bạn nên gói loại thứ này vào một thói quen bảo trì nào đó. Điều này có thể đơn giản như một thủ tục được lưu trữ xử lý nó trong một số điều kiện, một công việc cron hoặc bất cứ điều gì. Thông thường phân vùng theo ngày, nhưng tôi cũng thấy mình phân vùng theo phân bổ không gian bảng theo thời gian và điều đó yêu cầu một số thông tin bên ngoài - mất 30 phút để viết một trình giữ trẻ phân vùng là rất đáng để kiểm soát nó mang lại cho bạn.
zxq9

Hừ! Bạn có chắc là nó không chặn không? Tôi có một thiết lập tương tự, nhưng khi tôi chạy lệnh CLUSTER trên một phân vùng, một câu lệnh SELECT trên dữ liệu được giữ bởi các khối phân vùng khác!
E. van Putten

37

"Kế thừa bảng" có nghĩa là một cái gì đó khác với "kế thừa lớp" và chúng phục vụ các mục đích khác nhau.

Postgres là tất cả về định nghĩa dữ liệu. Đôi khi định nghĩa dữ liệu thực sự phức tạp. OOP (theo nghĩa thông thường có màu Java) là về các hành vi phụ thuộc vào các định nghĩa dữ liệu trong một cấu trúc nguyên tử đơn lẻ. Mục đích và ý nghĩa của từ "thừa kế" là khác nhau đáng kể ở đây.

Trong vùng đất OOP, tôi có thể định nghĩa (rất lỏng lẻo với cú pháp và ngữ nghĩa ở đây):

import life

class Animal(life.Autonomous):
  metabolism = biofunc(alive=True)

  def die(self):
    self.metabolism = False

class Mammal(Animal):
  hair_color = color(foo=bar)

  def gray(self, mate):
    self.hair_color = age_effect('hair', self.age)

class Human(Mammal):
  alcoholic = vice_boolean(baz=balls)

Các bảng cho điều này có thể giống như sau:

CREATE TABLE animal
  (name       varchar(20) PRIMARY KEY,
   metabolism boolean NOT NULL);

CREATE TABLE mammal
  (hair_color  varchar(20) REFERENCES hair_color(code) NOT NULL,
   PRIMARY KEY (name))
  INHERITS (animal);

CREATE TABLE human
  (alcoholic  boolean NOT NULL,
   FOREIGN KEY (hair_color) REFERENCES hair_color(code),
   PRIMARY KEY (name))
  INHERITS (mammal);

Nhưng đâu là những hành vi? Chúng không phù hợp với bất cứ đâu. Đây không phải là mục đích của "đối tượng" như chúng được thảo luận trong thế giới cơ sở dữ liệu, bởi vì cơ sở dữ liệu quan tâm đến dữ liệu, không phải mã thủ tục. Bạn có thể viết các hàm trong cơ sở dữ liệu để thực hiện các phép tính cho bạn (thường là một ý tưởng rất hay, nhưng không thực sự là một cái gì đó phù hợp với trường hợp này) nhưng các hàm không giống với các phương thức - các phương thức như được hiểu ở dạng OOP mà bạn đang nói về là cố tình kém linh hoạt.

Có một điều nữa cần chỉ ra về tính kế thừa như một thiết bị giản đồ: Kể từ Postgres 9.2, không có cách nào để tham chiếu một ràng buộc khóa ngoại trên tất cả các phân vùng / thành viên họ bảng cùng một lúc. Bạn có thể viết kiểm tra để thực hiện việc này hoặc thực hiện theo cách khác, nhưng nó không phải là một tính năng được tích hợp sẵn (nó thực sự gây ra các vấn đề với lập chỉ mục phức tạp, và không ai đã viết các bit cần thiết để làm cho nó tự động). Thay vì sử dụng kế thừa bảng cho mục đích này, thường thì kết hợp tốt hơn trong cơ sở dữ liệu để kế thừa đối tượng là tạo các phần mở rộng giản đồ cho các bảng. Một cái gì đó như thế này:

CREATE TABLE animal
  (name       varchar(20) PRIMARY KEY,
   ilk        varchar(20) REFERENCES animal_ilk NOT NULL,
   metabolism boolean NOT NULL);

CREATE TABLE mammal
  (animal      varchar(20) REFERENCES animal PRIMARY KEY,
   ilk         varchar(20) REFERENCES mammal_ilk NOT NULL,
   hair_color  varchar(20) REFERENCES hair_color(code) NOT NULL);


CREATE TABLE human
  (mammal     varchar(20) REFERENCES mammal PRIMARY KEY,
   alcoholic  boolean NOT NULL);

Bây giờ chúng ta có một tham chiếu chính tắc cho ví dụ của động vật mà chúng ta có thể tin cậy sử dụng làm tham chiếu khóa ngoại và chúng ta có một cột "ilk" tham chiếu đến một bảng định nghĩa xxx_ilk trỏ đến bảng "tiếp theo" của dữ liệu mở rộng ( hoặc cho biết không có nếu ilk là loại chung). Việc viết các hàm bảng, khung nhìn, v.v. chống lại loại lược đồ này dễ dàng đến mức hầu hết các khung ORM thực hiện chính xác loại điều này trong nền khi bạn sử dụng kế thừa lớp kiểu OOP để tạo các họ kiểu đối tượng.


Điều gì sẽ xảy ra nếu bạn đang thêm mọi mamal đã biết? Bạn sẽ thừa kế từ động vật có vú hoặc có một khóa ngoại như bạn đã làm ở đây? Vấn đề tôi gặp phải với các khóa ngoại là bạn phải thực hiện quá nhiều phép nối.
puk,

1
@puk Trước tiên, bạn cần phải quyết định tại sao bạn lại thêm mọi động vật có vú đã biết. Hình dạng của dữ liệu sẽ được xác định theo cách mà dữ liệu sẽ được sử dụng (có thể không cần thiết phải có một bảng cho mỗi con vật trong trường hợp này - hãy xem xét cơ sở dữ liệu cho thú ăn chơi nơi bạn thực sự có mọi loại đám đông ). Trong trường hợp trên, tôi thường thêm một chế độ xem là trường hợp phổ biến nhất mammal JOIN human, chỉ vì việc viết một phép nối mỗi lần như vậy rất khó chịu. Nhưng đừng tránh tham gia . Tham gia là những gì đặt R trong RDBMS. Nếu bạn không thích các phép nối, bạn nên sử dụng một loại db khác.
zxq9

@ zxq9: Tôi đoán rằng các liên kết lớn, không hiệu quả do các bảng lớn là nơi các chế độ xem cụ thể hóa phát huy tác dụng? (Tôi đã không sử dụng Postgres trong thời gian dài)
Mark K Cowan

1
@MarkKCowan Tham gia không phải là kém hiệu quả. Điều không hiệu quả là cố gắng tham gia vào các trường không được lập chỉ mục, không phải là duy nhất (vì lược đồ không ở bất kỳ nơi nào gần được chuẩn hóa) do thiết kế cẩu thả. Trong những trường hợp đó, một cái nhìn cụ thể hóa có thể hữu ích. Chế độ xem vật chất hóa cũng hữu ích trong trường hợp bạn cần dữ liệu chuẩn hóa làm nền tảng sơ đồ của mình (thường đúng), nhưng cũng cần một số biểu diễn làm việc, không chuẩn hóa dễ làm việc hơn cho hiệu quả xử lý (tải trước tính toán) hoặc hiệu quả nhận thức. Tuy nhiên, nếu bạn viết nhiều hơn đọc, thì đó là một sự bi quan.
zxq9 14/12/16

1
@MarkKCowan "Chậm" là một thuật ngữ tương đối. Trong các hệ thống doanh nghiệp lớn và máy chủ trò chơi, nơi chúng tôi có thể chấp nhận ~ 50ms để trả về một truy vấn, 20 phép nối bảng chưa bao giờ là vấn đề (dù sao trong Postgres 8+) theo kinh nghiệm của tôi. Nhưng trong trường hợp ban quản lý muốn <1ms phản hồi cho> 10b hàng tham gia trên 5 bảng trên dữ liệu chưa lập chỉ mục (hoặc giá trị dẫn xuất!) ... thì không hệ thống nào trên thế giới cảm thấy "nhanh" ngoài việc thực hiện tham gia này vào tháng trước và lưu trữ nó trong một cửa hàng K / V nhanh (về cơ bản là chế độ xem hiện thực hóa có thể hoạt động như trong những trường hợp đặc biệt). Không thể thoát khỏi sự đánh đổi về thời gian ghi hoặc đọc.
zxq9

6

Kế thừa có thể được sử dụng trong mô hình OOP miễn là bạn không cần tạo khóa ngoại trên bảng mẹ. Ví dụ: nếu bạn có một phương tiện lớp trừu tượng được lưu trữ trong bảng phương tiện và một ô tô trong bảng kế thừa từ nó, tất cả các ô tô sẽ hiển thị trong bảng phương tiện nhưng khóa ngoại từ bảng điều khiển trên bảng phương tiện sẽ không khớp với các chủ đề Hồ sơ.

Kế thừa cũng có thể được sử dụng như một công cụ phân vùng . Điều này đặc biệt hữu ích khi bạn có các bảng được phát triển mãi mãi (bảng nhật ký, v.v.).


1
Các ràng buộc bảng không được kế thừa, vì vậy nó không chỉ là các khóa ngoại. Bạn có thể áp dụng các ràng buộc bảng trên (các) bảng con khi chúng được tạo trong DDL của bạn hoặc bạn có thể viết các trình kích hoạt để thực hiện các ràng buộc tương tự.
Wexxor

3

Công dụng chính của thừa kế là để phân vùng, nhưng đôi khi nó hữu ích trong các tình huống khác. Trong cơ sở dữ liệu của tôi có nhiều bảng chỉ khác nhau ở một khóa ngoại. Bảng "lớp trừu tượng" của tôi "hình ảnh" chứa một "ID" (khóa chính của nó phải có trong mọi bảng) và raster PostGIS 2.0. Các bảng kế thừa chẳng hạn như "site_map" hoặc "Arti_drawing" có cột khóa ngoại (cột văn bản "site_name" cho "site_map", cột số nguyên "tạo tác" cho bảng "tạo tác", v.v.) và các ràng buộc khóa chính và khóa ngoài; phần còn lại được kế thừa từ bảng "hình ảnh". Tôi nghi ngờ rằng mình có thể phải thêm cột "mô tả" vào tất cả các bảng hình ảnh trong tương lai, vì vậy, điều này có thể giúp tôi tiết kiệm khá nhiều công việc mà không gây ra các vấn đề thực sự (tốt,

CHỈNH SỬA: một công dụng tốt khác: với xử lý hai bảng của người dùng chưa đăng ký , các RDBMS khác gặp vấn đề với việc xử lý hai bảng, nhưng trong PostgreSQL thì rất dễ dàng - chỉ cần thêm ONLYkhi bạn không bị vướng vào dữ liệu trong bảng "người dùng chưa đăng ký" kế thừa.


2

Kinh nghiệm duy nhất mà tôi có với các bảng kế thừa, đó là phân vùng. Nó hoạt động tốt nhưng không phải là phần phức tạp và dễ sử dụng nhất của PostgreSQL.

Tuần trước, chúng tôi đã xem xét vấn đề OOP tương tự, nhưng chúng tôi gặp quá nhiều vấn đề với Hibernate (không giống như thiết lập của chúng tôi), vì vậy chúng tôi không sử dụng kế thừa trong PostgreSQL.


0

Tôi sử dụng kế thừa khi tôi có nhiều hơn mối quan hệ 1-1 giữa các bảng.

Ví dụ: giả sử bạn muốn lưu trữ các vị trí trên bản đồ đối tượng với các thuộc tính x, y, xoay, tỷ lệ.

Bây giờ, giả sử bạn có một số loại đối tượng khác nhau để hiển thị trên bản đồ và mỗi đối tượng có các thông số vị trí bản đồ riêng và các thông số bản đồ không bao giờ được sử dụng lại.

Trong những trường hợp này, kế thừa bảng sẽ khá hữu ích để tránh phải duy trì các bảng không chuẩn hoặc phải tạo id vị trí và tham chiếu chéo nó đến các bảng khác.


-4

Sử dụng nó càng ít càng tốt. Và điều đó thường có nghĩa là không bao giờ, nó bùng phát thành một cách tạo ra cấu trúc vi phạm mô hình quan hệ, chẳng hạn bằng cách phá vỡ nguyên tắc thông tin và bằng cách tạo ra các túi thay vì các quan hệ.

Thay vào đó, hãy sử dụng phân vùng bảng kết hợp với mô hình quan hệ thích hợp, bao gồm các dạng thông thường khác.


4
Không đúng khi tính năng kế thừa PostgreSQLs vi phạm mô hình quan hệ bằng cách phá vỡ nguyên tắc thông tin. Nguyên tắc thông tin nói rằng tất cả dữ liệu trong cơ sở dữ liệu quan hệ được biểu diễn bằng các giá trị dữ liệu trong các quan hệ và tất cả các kết quả truy vấn lại được biểu diễn dưới dạng một quan hệ. ( En.wikipedia.org/wiki/Relational_model ) Điều này luôn đúng, vì tất cả các bảng , kế thừa một bảng khác, lại là các bảng đơn giản. Vì lý do đó, cũng không có cái gọi là "túi", bất kể điều đó có nghĩa là gì.
Roland

2
Chà, Wikipedia hầu như không phải là một tài liệu tham khảo về mô hình quan hệ; nó từ chối nhận ra SQL vi phạm mô hình quan hệ. Một cái túi là một cái bàn không có chìa khóa, vì có khả năng nó có các bản sao, do đó không phải là một quan hệ; một quan hệ phải là một tập hợp.
Leandro

Đó không phải là vấn đề của bản thân tính năng, mà là cách nó được sử dụng. Nếu bạn làm việc với uuids làm mã định danh, bạn sẽ có các khóa duy nhất trên tất cả các bảng con.
Roland

Bạn có lý, nhưng vấn đề ở đây là tính kế thừa dẫn đến việc modeller bỏ qua mô hình quan hệ. UUID không phải là khóa thực mà là khóa thay thế. Người ta vẫn phải khai báo các khóa tự nhiên.
Leandro
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.