Sử dụng đúng các bảng tra cứu


25

Tôi gặp khó khăn khi tìm ra chính xác làm thế nào để đặt ranh giới tốt cho thời điểm và nơi sử dụng bảng tra cứu trong cơ sở dữ liệu. Hầu hết các nguồn mà tôi đã xem đều nói rằng tôi không bao giờ có thể có quá nhiều, nhưng tại một số điểm, có vẻ như cơ sở dữ liệu sẽ được chia thành nhiều phần, trong khi nó có thể hiệu quả, nó không còn có thể quản lý được. Đây là một ví dụ tổng hợp về những gì tôi đang làm việc với:

Giả sử tôi có một bảng gọi là Nhân viên:

ID  LName   FName   Gender  Position
1   Doe     John    Male    Manager
2   Doe     Jane    Female  Sales
3   Smith   John    Male    Sales

Giả vờ một lúc rằng dữ liệu phức tạp hơn và chứa hàng trăm hàng. Điều rõ ràng nhất tôi thấy có thể được chuyển sang bảng tra cứu sẽ là Vị trí. Tôi có thể tạo một bảng có tên là Vị trí và dán các khóa ngoại từ bảng Vị trí vào bảng Nhân viên trong cột Vị trí.

ID  Position
1   Manager
2   Sales

Nhưng tôi có thể tiếp tục chia thông tin thành các bảng tra cứu nhỏ hơn bao xa trước khi nó không thể quản lý được? Tôi có thể tạo bảng Giới tính và có 1 tương ứng với Nam và 2 tương ứng với Nữ trong một bảng tra cứu riêng. Tôi thậm chí có thể đặt LNames và FNames vào các bảng. Tất cả các mục nhập "John" được thay thế bằng khóa ngoại là 1 trỏ đến bảng FName có ID là 1 tương ứng với John. Tuy nhiên, nếu bạn đi xuống lỗ thỏ này quá xa như thế này, thì bảng Nhân viên của bạn sẽ bị giảm xuống thành một mớ khóa ngoại:

ID  LName   FName   Gender  Position
1   1       1       1       1
2   1       2       2       2
3   2       1       1       2

Mặc dù điều này có thể hoặc không hiệu quả hơn đối với máy chủ để xử lý, nhưng điều này chắc chắn là không thể đọc được đối với một người bình thường có thể đang cố gắng duy trì nó và gây khó khăn hơn cho nhà phát triển ứng dụng khi cố gắng truy cập. Vì vậy, câu hỏi thực sự của tôi là bao xa là quá xa? Có "thực hành tốt nhất" cho loại điều này hoặc một bộ hướng dẫn tốt ở đâu đó không? Tôi không thể tìm thấy bất kỳ thông tin trực tuyến nào thực sự đưa ra một bộ hướng dẫn tốt, có thể sử dụng được cho vấn đề cụ thể này mà tôi đang gặp phải. Thiết kế cơ sở dữ liệu là mũ cũ đối với tôi nhưng thiết kế cơ sở dữ liệu TỐT còn rất mới nên các câu trả lời kỹ thuật quá mức có thể nằm trên đầu tôi. Bất kỳ trợ giúp sẽ được đánh giá cao!


5
Sử dụng bảng "tra cứu" là một điều. Thay thế văn bản bằng số id là một điều hoàn toàn khác.
Mike Sherrill 'Nhớ lại mèo'

1
Giới tính có thể không luôn luôn được cố định thành 2 giá trị! Bây giờ chúng ta có sự chuyển đổi giới tính, người muốn nói rằng một ứng dụng có thể không cần các danh mục bổ sung như 'nam sinh ra bây giờ là nữ' hoặc 'nữ sinh ra bây giờ là nam'.

@Mike, bình luận tốt!
Walter Mitty

Trong cửa hàng của tôi, các nhà tư tưởng đã có thể dừng lại chỉ sau bốn lựa chọn, nam, nữ, chuyển giới, sẽ không tiết lộ.
kevinsky

Câu trả lời:


22

Nhưng tôi có thể tiếp tục chia thông tin thành các bảng tra cứu nhỏ hơn bao xa trước khi nó không thể quản lý được? Tôi có thể tạo bảng Giới tính và có 1 tương ứng với Nam và 2 tương ứng với Nữ trong một bảng tra cứu riêng.

Bạn đang trộn lẫn hai vấn đề khác nhau. Một vấn đề là việc sử dụng bảng "tra cứu"; khác là việc sử dụng các khóa thay thế (số id).

Bắt đầu với bảng này.

ID  LName   FName   Gender  Position
1   Doe     John    Male    Manager
2   Doe     Jane    Female  Sales
3   Smith   John    Male    Sales

Bạn có thể tạo bảng "tra cứu" cho các vị trí như thế này.

create table positions (
  pos_name varchar(10) primary key
);

insert into positions
select distinct position 
from employees;

alter table employees
add constraint emp_fk1
foreign key (position) 
  references positions (pos_name);

Bảng gốc của bạn trông giống hệt như trước khi tạo bảng "tra cứu". Và bảng nhân viên không yêu cầu tham gia bổ sung để có được dữ liệu hữu ích, có thể đọc được từ con người.

Sử dụng bảng "tra cứu" sẽ hiểu rõ điều này: Ứng dụng của bạn có cần kiểm soát các giá trị đầu vào mà tham chiếu khóa ngoài cung cấp không? Nếu vậy, bạn luôn có thể sử dụng bảng "tra cứu". (Bất kể nó có sử dụng khóa thay thế hay không.)

Trong một số trường hợp, bạn sẽ có thể điền hoàn toàn bảng đó vào thời gian thiết kế. Trong các trường hợp khác, người dùng cần có thể thêm hàng vào bảng đó trong thời gian chạy. (Và có lẽ bạn sẽ cần bao gồm một số quy trình quản trị để xem xét dữ liệu mới.) Giới tính, thực sự có tiêu chuẩn ISO , có thể được điền hoàn toàn vào thời điểm thiết kế. Tên đường cho đơn đặt hàng sản phẩm trực tuyến quốc tế có thể phải được thêm vào thời gian chạy.


2
Tôi không biết bạn có thể làm tất cả điều đó! Cách thức hoạt động của phương pháp của bạn thật tuyệt vời. Cảm ơn bạn!
Brad Turner

4
Tôi đã tham gia DBA Stack Exchange chỉ để tôi có thể bình chọn câu trả lời này. Điều này là đẹp và không bao giờ xảy ra với tôi. Cảm ơn!
CindyH

Tôi đánh giá cao phương pháp để điền vào bảng tra cứu. Lý do của tôi để đọc câu hỏi này là để xem liệu sẽ có một lợi ích mà tôi không thể thấy đối với khóa thay thế trên các bảng tra cứu của mình. Bạn xác nhận cho tôi một trường văn bản duy nhất là tốt và hữu ích như nó xuất hiện. Cảm ơn bạn.
Sinthia V

8

Trong bảng Nhân viên của bạn, tôi chỉ có một tra cứu cho "Vị trí" vì đó là một bộ dữ liệu giới hạn có thể mở rộng.

  • Giới tính là tự mô tả (nói Mhoặc F), giới hạn ở 2 giá trị và có thể được thực thi với ràng buộc KIỂM TRA. Bạn sẽ không thêm các Giới tính mới (bỏ qua các bollocks chính trị)
  • Tên đầu tiên "John" không phải là một phần của bộ dữ liệu bị giới hạn, bị hạn chế: bộ dữ liệu tiềm năng rất lớn đến mức vô hạn vì vậy nó không nên là một tra cứu

Nếu bạn muốn thêm một Vị trí mới, bạn chỉ cần thêm một hàng vào bảng tra cứu. Điều này cũng loại bỏ sự bất thường sửa đổi dữ liệu là một điểm của chuẩn hóa

Ngoài ra, một khi bạn có một triệu nhân viên thì việc lưu trữ PositionID nhỏ hơn sẽ hiệu quả hơn so với varchar.

Hãy thêm một cột "tiền lương" mới. Tôi sẽ sử dụng bảng tra cứu tại đây với khóa CHF, GBP, EUR, USD, v.v .: Tôi sẽ không sử dụng khóa thay thế. Điều này có thể bị hạn chế với ràng buộc KIỂM TRA như Giới tính nhưng nó là một tập hợp dữ liệu hạn chế nhưng có thể mở rộng như Vị trí. Tôi đưa ra ví dụ này vì tôi sử dụng khóa tự nhiên ngay cả khi nó xuất hiện trong một triệu hàng dữ liệu nhân viên mặc dù là char (3) chứ không phải là tinyint

Vì vậy, để tóm tắt, bạn sử dụng bảng tra cứu

  1. nơi bạn có dữ liệu được đặt hữu hạn nhưng có thể mở rộng trong một cột
  2. nơi không tự mô tả
  3. để tránh dị thường sửa đổi dữ liệu

1
Một lý do có thể để đưa giới vào bảng tra cứu là nội địa hóa.
a_horse_with_no_name

1
"Giới ... Nam tính ',' Nữ tính ') khi họ có nghĩa là "tình dục" (' Nam ',' Nữ '). Nếu bối cảnh là giới tính ngữ pháp thì thường có nhiều hơn hai giá trị. Nếu bối cảnh ghi lại giới tính của trẻ sơ sinh thì có ít nhất bốn giá trị ('chưa được đánh giá chính thức' và 'đánh giá chính thức là không thuyết phục'). ps Tôi không có ý nói khó nghe, tôi rất thích sự trớ trêu :)
onedaywhen

4
@encedaywhen: giá trị chính xác cho một cột có tên là "Giới tính" là "Có làm ơn". Trừ khi bạn là người Anh
gbn

Thuật ngữ "dị thường" đang bị sử dụng sai ở đây vì thuật ngữ này có ý nghĩa đặc biệt khác liên quan đến bình thường hóa và liên kết là không phù hợp.
philipxy

5

Câu trả lời là "nó phụ thuộc". Không thỏa mãn lắm nhưng có nhiều ảnh hưởng đẩy và kéo thiết kế. Nếu bạn có các lập trình viên ứng dụng thiết kế cơ sở dữ liệu, một cấu trúc như bạn mô tả sẽ hoạt động cho họ vì ORM che giấu sự phức tạp. Bạn sẽ nhổ tóc khi viết báo cáo và phải tham gia mười bảng để có địa chỉ.

Thiết kế để sử dụng, dự định sử dụng và có khả năng sử dụng trong tương lai. Đây là nơi kiến ​​thức của bạn về quy trình kinh doanh xuất hiện. Nếu bạn đang thiết kế cơ sở dữ liệu cho một doanh nghiệp thú y, có những giả định hợp lý về quy mô, cách sử dụng và phương hướng trong chức năng sẽ khác hoàn toàn so với khởi nghiệp công nghệ cao.

Để sử dụng lại một trích dẫn yêu thích

"Một người đàn ông khôn ngoan đã từng nói với tôi" bình thường hóa cho đến khi nó đau, không chuẩn hóa cho đến khi nó hoạt động ".

Đâu đó trong đó là điểm ngọt ngào. Kinh nghiệm của tôi là việc có một id khóa trong nhiều bảng không phải là một tội nghiêm trọng như một số người nghĩ nếu bạn không bao giờ thay đổi khóa chính.

Lấy ví dụ viết tắt này của các bảng được chuẩn hóa cao từ một hệ thống thực

CREATE TABLE PROPERTY
(ID                          NUMBER(9)           NOT NULL);

CREATE TABLE PROPERTY_TYPE
(ID                          NUMBER(9)           NOT NULL);

CREATE TABLE PROPERTY_LOCALE 
PROPERTY_ID                  NUMBER(9)           NOT NULL,
(LOCALE_ID                   NUMBER(9)           NOT NULL,  --language 
VALUE                        VARCHAR2(200)       NOT NULL);

CREATE TABLE PROPERTY_DEPENDENCY
(PROPERTY_ID                 NUMBER(9)           NOT NULL,
 PARENT_PROPERTY_ID          NUMBER(9)                   ,
 PROPERTY_TYPE_ID            NUMBER(9)           NOT NULL);

Các bảng này thiết lập một danh sách liên kết các thuộc tính đơn và thuộc tính cha mẹ và chúng được sử dụng ở đây

  CREATE TABLE CASE_PROPERTY
  (ID                        NUMBER(9)           NOT NULL,
  PARENT_ID                  NUMBER(9),
  CASE_ID                    NUMBER(9)           NOT NULL,
  PROPERTY_ID                NUMBER(9),
  PROPERTY_TYPE_ID           NUMBER(9)           NOT NULL);

Điều này có vẻ tốt: nhận tất cả các trường hợp với property_id trong một lựa chọn

Hãy lấy một danh sách để chọn từ

 Select pl.value, pd.property_id
 from property_locale pl, property_dependency pd
 where pl.property_id = pd.property_id
 and pd.property_type_id = 2;  --example number

Bây giờ hãy thử chọn tất cả các thuộc tính của một trường hợp nếu nó có property_types là 3 và 4 và 5, hoặc không ...

SELECT   cp2.case_id,
         (SELECT   pl.VALUE
            FROM   case_property cp, property_locale pl
           WHERE       cp.property_id = pl.property_id
                   AND CP.PROPERTY_TYPE_ID = 2
                   AND pl.locale_id = 2
                   AND cp.case_id = cp2.case_id)
            AS VALUE1,
         (SELECT   pl.VALUE
            FROM   case_property cp, property_locale pl
           WHERE       cp.property_id = pl.property_id
                   AND CP.PROPERTY_TYPE_ID = 34
                   AND pl.locale_id = 2
                   AND cp.case_id = cp2.case_id)
            AS VALUE2,
         (SELECT   pl.VALUE
            FROM   case_property cp, property_locale pl
           WHERE       cp.property_id = pl.property_id
                   AND CP.PROPERTY_TYPE_ID = 4
                   AND pl.locale_id = 2
                   AND cp.case_id = cp2.case_id)
            AS VALUE3
  FROM   case_property cp2
 WHERE   cp2.case_id = 10293  

Điều này chỉ làm tổn thương ... ngay cả khi bạn sử dụng những cách thanh lịch hơn để đối phó với điều này. Tuy nhiên, thêm một chút khử chuẩn hóa bằng cách phá vỡ các thuộc tính mà một trường hợp sẽ chỉ có một property_id và điều này có thể tốt hơn nhiều.

Để tìm ra khi nào bạn có quá nhiều bảng hoặc không đủ, hãy thử truy vấn cơ sở dữ liệu với các câu hỏi của ứng dụng, một báo cáo và phân tích hàng năm sẽ sử dụng.


5
Số ID không liên quan gì đến việc chuẩn hóa. Chỉ vì mỗi bảng có số id không có nghĩa là trong 5NF hoặc thậm chí là 3NF. Điều đó chỉ có nghĩa là bạn phải thực hiện nhiều lần tham gia để có được dữ liệu có thể sử dụng được từ bảng đó.
Mike Sherrill 'Nhớ lại mèo'
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.