Có hợp lý để đánh dấu tất cả các cột nhưng một cột là khóa chính không?


9

Tôi có một bảng đại diện cho phim. Các lĩnh vực là :
id (PK), title, genre, runtime, released_in, tags, origin, downloads.

Cơ sở dữ liệu của tôi không thể bị ô nhiễm bởi các hàng trùng lặp, vì vậy tôi muốn thực thi tính duy nhất. Vấn đề là các bộ phim khác nhau có thể có cùng tiêu đề hoặc thậm chí cùng một lĩnh vực ngoại trừ tagsdownloads. Làm thế nào để thực thi tính độc đáo?

Tôi nghĩ về hai cách:

  • làm cho tất cả các trường trừ downloadskhóa chính. Tôi đang downloadstránh xa vì nó là JSON và nó có thể sẽ ảnh hưởng đến hiệu suất.
  • chỉ giữ idlàm khóa chính, nhưng thêm một ràng buộc duy nhất với tất cả các cột khác (ngoại trừ, một lần nữa, downloads).

Tôi đọc câu hỏi này rất giống nhau, nhưng tôi không hiểu tôi nên làm gì. Hiện tại bảng này không liên quan đến bất kỳ bảng nào khác, nhưng trong tương lai có thể.

Hiện tại tôi có ít hơn 20.000 hồ sơ, nhưng tôi hy vọng con số sẽ tăng lên. Tôi không biết điều này có liên quan đến vấn đề này không.

EDIT: Tôi đã sửa đổi lược đồ và đây là cách tôi sẽ tạo bảng:

CREATE TABLE movies (
    id          serial PRIMARY KEY,
    title       text NOT NULL,
    runtime     smallint NOT NULL CHECK (runtime >= 0),
    released_in smallint NOT NULL CHECK (released_in > 0),
    genres      text[] NOT NULL default ARRAY[]::text[],
    tags        text[] NOT NULL default ARRAY[]::text[],
    origin      text[] NOT NULL default ARRAY[]::text[],
    downloads   json NOT NULL,
    inserted_at timestamp NOT NULL default current_timestamp,
    CONSTRAINT must_be_unique UNIQUE(title,runtime,released_in,genres,tags,origin)
);

Tôi cũng đã thêm timestampcột, nhưng đó không phải là vấn đề vì tôi sẽ không chạm vào nó. Vì vậy, nó sẽ luôn luôn tự động và duy nhất.


Câu hỏi liên quan chặt chẽ (có câu trả lời) trên SO: Tôi có cần khóa chính cho bảng của mình không, có UNIQUE (4 cột tổng hợp), một trong số đó có thể là NULL không? . Nếu bất kỳ cột nào có thể là NULL, hãy khẩn trương xem xét điều này: dba.stackexchange.com/q/9759/3684 .
Erwin Brandstetter

Câu trả lời:


4

Định nghĩa bảng của bạn trông hợp lý tất cả hơn bây giờ. Với tất cả các cột NOT NULL, UNIQUEràng buộc sẽ hoạt động như mong đợi - ngoại trừ lỗi chính tả và những khác biệt nhỏ về chính tả, điều này có thể khá phổ biến tôi sợ. Hãy xem xét nhận xét của @ a_horse .

Thay thế bằng chỉ mục duy nhất chức năng

Tùy chọn khác sẽ là một chỉ mục duy nhất về chức năng (tương tự như những gì @Dave đã nhận xét ). Nhưng tôi sẽ sử dụng một uuidloại dữ liệu để tối ưu hóa kích thước và hiệu suất chỉ mục.

Truyền từ mảng sang văn bản là không IMMUTABLE(do thực hiện chung của nó):

Do đó bạn cần một hàm trợ giúp nhỏ để khai báo nó bất biến:

CREATE OR REPLACE FUNCTION f_movie_uuid(_title text
                                      , _runtime int2
                                      , _released_in int2
                                      , _genres text[]
                                      , _tags text[]
                                      , _origin text[])
  RETURNS uuid LANGUAGE sql IMMUTABLE AS  -- faking IMMUTABLE
'SELECT md5(_title || _runtime::text || _released_in::text
         || _genres::text || _tags::text || _origin::text)::uuid';

Sử dụng nó cho định nghĩa chỉ mục:

CREATE UNIQUE INDEX movies_uni_idx
ON movies (f_movie_uuid(title,runtime,released_in,genres,tags,origin));

Câu đố SQL.

Thêm chi tiết:

Bạn có thể sử dụng UUID được tạo dưới dạng PK, nhưng tôi vẫn sẽ sử dụng serialcột có 4 byte, đơn giản và rẻ tiền cho các tham chiếu FK và các mục đích khác. Một UUID sẽ là một lựa chọn tuyệt vời cho các hệ thống phân tán cần tạo ra các giá trị PK một cách độc lập. Hoặc đối với các bảng rất lớn, nhưng không có đủ phim trong hệ mặt trời của chúng ta cho điều đó.

Ưu và nhược điểm

Một ràng buộc duy nhất được thực hiện với một chỉ mục duy nhất trên các cột liên quan. Đặt các cột có liên quan trong định nghĩa ràng buộc trước và bạn có một chỉ mục hữu ích cho các mục đích khác là lợi ích tài sản thế chấp.

Có những lợi ích cụ thể khác, đây là một danh sách:

Các chỉ số duy nhất chức năng là (có khả năng nhiều) kích thước nhỏ hơn, có thể làm cho nó nhanh hơn đáng kể. Nếu các cột của bạn không quá lớn, sự khác biệt sẽ không nhiều. Ngoài ra còn có chi phí nhỏ cho việc tính toán.

Nối tất cả các cột có thể giới thiệu dương tính giả ( 'foo ' || 'bar' = 'foob ' || 'ar'nhưng điều đó dường như rất khó xảy ra trong trường hợp này. Typose rất nhiều khả năng bạn có thể bỏ qua nó một cách an toàn ở đây.

Tính độc đáo và mảng

Mảng sẽ phải được sắp xếp một cách nhất quán để có ý nghĩa trong bất kỳ sự sắp xếp độc đáo nào dựa vào =toán tử bởi vì '{1,2}' <> '{2,1}'. Tôi đề nghị bảng look-up cho genre, tagoriginvới serialPK và mục duy nhất, cho phép tìm kiếm mờ cho các phần tử mảng. Sau đó:

Dù bằng cách nào, làm việc với các mảng trực tiếp hoặc với một lược đồ được chuẩn hóa và một khung nhìn cụ thể hóa, việc tìm kiếm có thể rất hiệu quả với chỉ mục và toán tử phù hợp:

Qua một bên

Nếu bạn đang sử dụng Postgres 9.4 trở lên, hãy cân nhắc jsonbthay vìjson .


6

Hãy tưởng tượng bạn ra ngoài với một nhóm bạn và cuộc trò chuyện chuyển sang phim. Có người hỏi: "Bạn nghĩ gì về 'Ba chàng lính ngự lâm'?" Bạn trả lời, "Cái nào?"

Bạn cần thêm thông tin gì để chắc chắn rằng cả hai bạn đều nghĩ về cùng một bộ phim? Tên giám đốc? Xưởng sản xuất? Năm nó được phát hành? Một trong những tên của ngôi sao? Một số kết hợp của hai hoặc nhiều?

Câu trả lời cho câu hỏi của tôi và của bạn là như nhau.

Tuy nhiên, tôi sẽ không nghĩ rằng thể loại đó sẽ là một ứng cử viên tốt. Một lý do, thể loại là quá nhiều chủ quan một tiêu chí. Là 'Ba chàng lính ngự lâm'? kịch? cuộc phiêu lưu? phim hài? phiêu lưu hành động? hài kịch lãng mạn? Tôi thường thấy cùng một bộ phim được liệt kê dưới các thể loại khác nhau. Ngay cả khi bạn cho phép nhiều thể loại, người dùng của bạn có thể chọn một thể loại hoàn toàn khác không được liệt kê với phim thực tế mà họ đang tìm kiếm.

Ngay cả thời gian chạy cũng có thể khác nhau, đặc biệt là giữa các phiên bản rạp hát và VCR / DVD / b-ray.

Vì vậy, bạn cần các thuộc tính khách quan, cứng sẽ không thay đổi từ bản phát hành phương tiện này sang bản phát hành khác. Thật không may, điều đó có thể loại trừ tên của bộ phim vì phim đã được đổi tên, đặc biệt là sau khi phát hành phần tiếp theo.

Ngày phát hành thì sao? Bản phát hành sân khấu năm 1993? Bản phát hành VCR năm 1999? Phát hành DVD năm 2004? Bạn có được ý tưởng.

Hãy suy nghĩ về nó, những gì trong tất cả những bộ phim được đạo diễn bởi Alan Smithee? Liệu giám đốc thực sự có bao giờ bước tới để đưa tên tuổi của mình vào dự án sau khi thực tế? Tôi không biết.

Hmm, tôi nên dừng lại trong khi vẫn còn một số tiêu chí.

Một số điểm bổ sung:

  • Có, giữ khóa thay thế và tạo một chỉ mục duy nhất trên các trường khóa tự nhiên (nếu cuối cùng bạn có thể đóng đinh chúng xuống). Khóa thay thế là tốt nhất cho các tham chiếu khóa ngoài. Bạn không muốn sao chép tất cả các trường khóa tự nhiên trong mỗi bảng có chứa tham chiếu đến phim.
  • Thả các trường mảng (thể loại, thẻ, nguồn gốc). Đi trước và bình thường hóa đúng các thuộc tính. Tôi chưa bao giờ thấy một lĩnh vực mảng không phải là vấn đề lớn hơn nó đáng giá, đặc biệt là nếu bạn muốn chúng có thể tìm kiếm được ("... trong đó thể loại = 'kinh dị' ..."). Lưu ý điều này sẽ không tự động loại bỏ bất kỳ vấn đề nào với sự khác biệt về trường hợp và chính tả ("Khoa học viễn tưởng" so với "SciFi") - trừ khi bạn duy trì đúng các bảng tra cứu . Nhưng việc kiểm tra sự khác biệt trong một lĩnh vực của một bảng nhỏ sẽ dễ dàng hơn rất nhiều so với mọi ô của mỗi hàng của một bảng lớn.

4

Cột ID hoàn toàn không có lợi thế khi nói đến tính duy nhất bạn muốn / cần thực thi. Tính duy nhất của bất kỳ sự kết hợp thuộc tính nào sẽ không bao giờ được thực thi bằng cách thêm ID vô nghĩa. "Ưu điểm" của nó chỉ hiển thị khi bạn đạt đến điểm mà bạn cần một bảng mới cần khóa ngoại cho bảng này. Trong trường hợp đó và NẾU bạn đã bao gồm Id, thì bạn có thể sử dụng Id đó làm FK trong bảng mới của mình. (Nhưng đừng nghĩ rằng đó sẽ là một bữa ăn trưa miễn phí. Nhược điểm của cách tiếp cận như vậy là bạn sẽ thấy mình viết nhiều bài tham gia hơn cho mục đích tìm nạp thông tin hoàn toàn có thể là một phần của bảng mới mà bạn đã tạo. )


1
Nếu quy tắc kinh doanh nói rằng sự kết hợp của các giá trị trong các thuộc tính FOO và BAR phải là duy nhất, thì việc thêm ID sẽ không đạt được điều đó. Thêm ID chỉ tạo điều kiện tránh việc phải bao gồm FOO và BAR như vậy trong các bảng tham chiếu. Đến lượt nó đòi hỏi phải tham gia nhiều hơn vì các thuộc tính FOO và BAR (mang định danh KINH DOANH) không phải là nơi chúng có thể (và là nơi chúng rất có khả năng MỞ RỘNG, ít nhất là theo quan điểm kinh doanh).
Erwin Smout

1
Đó không phải là "hàng" phải là duy nhất, đó là những gì doanh nghiệp nói là định danh của họ phải là. Nếu đó là sự kết hợp của các thuộc tính FOO và BAR, thì đó là sự kết hợp của các thuộc tính FOO và BAR.
Erwin Smout

2
Có Id hay không không giải quyết được bất kỳ vấn đề nào về việc thực thi tính duy nhất của các cột "kinh doanh" trong bảng của bạn. Việc thực thi tính duy nhất phải được thực hiện bằng cách khai báo các khóa thích hợp (mà bạn làm - thực tế là bạn đã sử dụng từ cú pháp "CONSTRAINT" thay vì "KEY" không có nghĩa đó không phải là khóa).
Erwin Smout
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.