Tại sao bạn sẽ lưu trữ một enum trong DB?


69

Tôi đã thấy một số câu hỏi, như thế này , xin lời khuyên về cách lưu trữ enum trong DB. Nhưng tôi tự hỏi tại sao bạn sẽ làm điều đó. Vì vậy, hãy nói rằng tôi có một thực thể Personvới một genderlĩnh vực và một Genderenum. Sau đó, bảng người của tôi có một giới tính cột.

Bên cạnh lý do rõ ràng về việc thực thi tính đúng đắn, tôi không hiểu tại sao tôi sẽ tạo một bảng bổ sung genderđể ánh xạ những gì tôi đã có trong ứng dụng của mình. Và tôi không thực sự thích có sự trùng lặp đó.



1
Nơi nào khác bạn sẽ lưu trữ dữ liệu có thể thay đổi thường xuyên? Trong khi bạn có thể đã nghĩ về tất cả các tùy chọn nếu có ai đó đi cùng và muốn thêm một tùy chọn mới. Bạn đã sẵn sàng để điều chỉnh danh sách mã hóa cứng? Ai đó có thể muốn đưa ra giới tính của họ như một cái gì đó khác với nam hay nữ, ví dụ như liên giới tính chẳng hạn.
JB King

4
@JBKing ... chỉ cần nhìn vào danh sách giới tính của Facebook.


3
Nếu khách hàng của bạn là "Tumblrites ảo tưởng", thì bạn cũng nên tạo một lược đồ cơ sở dữ liệu cho phép bạn tạo ra thứ gì đó phục vụ nhu cầu của họ, ít nhất, nếu bạn có ý định duy trì hoạt động kinh doanh.
Gort Robot

Câu trả lời:


74

Hãy lấy một ví dụ khác ít gây khó khăn hơn với các khái niệm và kỳ vọng. Tôi đã có một enum ở đây, và đó là tập hợp các ưu tiên cho một lỗi.

Giá trị nào bạn đang lưu trữ trong cơ sở dữ liệu?

Vì vậy, tôi có thể được lưu trữ 'C', 'H', 'M', và 'L'trong cơ sở dữ liệu. Hoặc 'HIGH'và như vậy. Điều này có vấn đề về dữ liệu gõ nghiêm ngặt . Có một bộ giá trị hợp lệ đã biết và nếu bạn không lưu trữ bộ đó trong cơ sở dữ liệu, có thể khó làm việc với nó.

Tại sao bạn lưu trữ dữ liệu trong mã?

Bạn đã có List<String> priorities = {'CRITICAL', 'HIGH', 'MEDIUM', 'LOW'};hoặc một cái gì đó để có hiệu lực trong mã. Điều đó có nghĩa là bạn đã có các ánh xạ khác nhau của dữ liệu này sang định dạng phù hợp (bạn đang chèn tất cả các giới hạn vào cơ sở dữ liệu, nhưng bạn đang hiển thị dưới dạng Critical). Mã của bạn bây giờ cũng khó bản địa hóa. Bạn đã ràng buộc biểu diễn cơ sở dữ liệu của ý tưởng vào một chuỗi được lưu trữ trong mã.

Bất cứ nơi nào bạn cần truy cập vào danh sách này, bạn cần phải sao chép mã hoặc một lớp với một loạt các hằng số. Không phải trong số đó là lựa chọn tốt. Bạn cũng không nên quên rằng có những ứng dụng khác có thể sử dụng dữ liệu này (có thể được viết bằng các ngôn ngữ khác - ứng dụng web Java có hệ thống báo cáo Crystal Báo cáo được sử dụng và dữ liệu cung cấp công việc hàng loạt Perl vào dữ liệu đó). Công cụ báo cáo sẽ cần biết danh sách dữ liệu hợp lệ (điều gì xảy ra nếu không có gì được đánh dấu 'LOW'ưu tiên và bạn cần biết rằng đó là ưu tiên hợp lệ cho báo cáo?), Và công việc hàng loạt sẽ có thông tin về những gì hợp lệ giá trị là.

Theo giả thuyết, bạn có thể nói "chúng tôi là một cửa hàng ngôn ngữ - mọi thứ đều được viết bằng Java" và có một .jar duy nhất chứa thông tin này - nhưng bây giờ điều đó có nghĩa là các ứng dụng của bạn được liên kết chặt chẽ với nhau và có chứa .jar dữ liệu. Bạn sẽ cần phát hành phần báo cáo và phần cập nhật hàng loạt cùng với ứng dụng web mỗi khi có thay đổi - và hy vọng rằng việc phát hành đó diễn ra suôn sẻ cho tất cả các phần.

Điều gì xảy ra khi sếp của bạn muốn một ưu tiên khác?

Ông chủ của bạn đến hôm nay. Có một ưu tiên mới - CEO. Bây giờ bạn phải đi và thay đổi tất cả các và thực hiện biên dịch lại và triển khai lại.

Với cách tiếp cận 'enum-in-the-the', bạn cập nhật danh sách enum để có mức độ ưu tiên mới. Tất cả các mã có được danh sách kéo nó từ cơ sở dữ liệu.

Dữ liệu hiếm khi đứng một mình

Với các ưu tiên, các khóa dữ liệu vào các bảng khác có thể chứa thông tin về quy trình công việc hoặc ai có thể đặt mức độ ưu tiên này hoặc không có gì.

Quay trở lại giới tính như đã đề cập trong câu hỏi một chút: Giới tính có một liên kết đến các đại từ đang sử dụng: he/his/himshe/hers/her... và bạn muốn tránh mã hóa cứng vào chính mã. Và sau đó, sếp của bạn đến và bạn cần thêm bạn đã có 'OTHER'giới tính (để đơn giản hóa) và bạn cần liên hệ giới tính này với they/their/them... và sếp của bạn thấy những gì Facebook có và ... tốt, vâng.

Bằng cách giới hạn bản thân vào một bit dữ liệu được gõ theo chuỗi chứ không phải bảng enum, giờ đây bạn cần sao chép chuỗi đó trong một loạt các bảng khác để duy trì mối quan hệ này giữa dữ liệu và các bit khác.

Còn các kho dữ liệu khác thì sao?

Bất kể nơi nào bạn lưu trữ này, cùng một nguyên tắc tồn tại.

  • Bạn có thể có một tập tin, priorities.propcó danh sách ưu tiên. Bạn đọc danh sách này từ một tập tin tài sản.
  • Bạn có thể có cơ sở dữ liệu lưu trữ tài liệu (như CouchDB ) có mục nhập enums(và sau đó viết hàm xác thực bằng JavaScript ):

    {
       "_id": "c18b0756c3c08d8fceb5bcddd60006f4",
       "_rev": "1-c89f76e36b740e9b899a4bffab44e1c2",
       "priorities": [ "critical", "high", "medium", "low" ],
       "severities": [ "blocker", "bad", "annoying", "cosmetic" ]
    }
    
  • Bạn có thể có một tệp XML với một chút lược đồ:

    <xs:element name="priority" type="priorityType"/>
    
    <xs:simpleType name="priorityType">
      <xs:restriction base="xs:string">
        <xs:enumeration value="critical"/>
        <xs:enumeration value="high"/>
        <xs:enumeration value="medium"/>
        <xs:enumeration value="low"/>
      </xs:restriction>
    </xs:simpleType>
    

Ý tưởng cốt lõi là như nhau. Kho lưu trữ dữ liệu chính là nơi danh sách các giá trị hợp lệ cần được lưu trữ và thi hành. Bằng cách đặt nó ở đây, sẽ dễ dàng hơn để suy luận về mã và dữ liệu. Bạn không phải lo lắng về việc kiểm tra phòng thủ những gì bạn có mỗi lần (đó là chữ hoa? Hoặc thấp hơn? Tại sao lại có một chriticalloại trong cột này? V.v ...) bởi vì bạn biết những gì bạn đang nhận được từ kho dữ liệu là chính xác những gì kho dữ liệu đang mong đợi bạn gửi khác - và bạn có thể truy vấn kho dữ liệu để biết danh sách các giá trị hợp lệ.

Mang đi

Tập hợp các giá trị hợp lệ là dữ liệu , không phải mã. Bạn làm cần phải phấn đấu cho DRY mã - nhưng vấn đề của sự trùng lặp là bạn đang sao chép các dữ liệu trong các mã, chứ không phải tôn trọng vị trí của nó như là dữ liệu và lưu trữ nó trong một cơ sở dữ liệu.

Nó giúp việc viết nhiều ứng dụng vào kho dữ liệu dễ dàng hơn và tránh có các trường hợp mà bạn sẽ cần triển khai mọi thứ được kết hợp chặt chẽ với chính dữ liệu - vì bạn chưa ghép mã của mình với dữ liệu.

Nó làm cho các ứng dụng thử nghiệm dễ dàng hơn vì bạn không phải kiểm tra lại toàn bộ ứng dụng khi CEOmức độ ưu tiên được thêm vào - bởi vì bạn không có bất kỳ mã nào quan tâm đến giá trị thực sự của mức độ ưu tiên.

Có thể suy luận về mã và dữ liệu độc lập với nhau giúp tìm và sửa lỗi dễ dàng hơn khi thực hiện bảo trì.


6
Nếu bạn có thể thêm một giá trị enum vào mã của mình mà không phải thay đổi bất kỳ logic nào (và e rằng đó là hiển thị cục bộ của nó), tôi nghi ngờ sự cần thiết cho giá trị enum bổ sung ở vị trí đầu tiên. Và trong khi tôi đủ tuổi để đánh giá khả năng dễ dàng truy vấn các bản sao lưu cơ sở dữ liệu bằng các truy vấn SQL đơn giản để phân tích một vấn đề, với ORM ngày nay bạn có thể làm rất tốt mà không cần phải xem xét cơ sở dữ liệu cơ bản. Tôi không hiểu điểm về nội địa hóa (đại từ) ở đây - những thứ đó chắc chắn không nên có trong cơ sở dữ liệu, nhưng các tệp tài nguyên thuộc loại nào đó tôi muốn nói.
Voo

1
@Voo các đại từ là một ví dụ về các dữ liệu khác liên quan đến giá trị này. Nếu không có dữ liệu trong một bảng, các giá trị được gõ theo chuỗi sẽ cần phải ở đó mà không có ràng buộc FK thích hợp. Nếu bạn có đại từ (như thế này) trong một tệp tài nguyên, bạn đã có sự kết hợp giữa cơ sở dữ liệu và tệp (cập nhật cơ sở dữ liệu và triển khai lại tệp). Hãy xem xét các enum của redmine có thể sửa đổi thông qua giao diện quản trị viên một cách nhanh chóng mà không cần phải triển khai lại.

1
... Cũng nhớ rằng cơ sở dữ liệu là một kho lưu trữ dữ liệu polyglot. Nếu bạn yêu cầu xác thực phải là một phần của ORM bằng một ngôn ngữ, bạn đã bắt buộc phải sao chép xác thực đó bằng bất kỳ ngôn ngữ nào khác mà bạn sử dụng (Gần đây tôi đã làm việc với giao diện người dùng Java có Python đẩy dữ liệu vào cơ sở dữ liệu - ORM Java và các hệ thống Python phải đồng ý về mọi thứ - và thỏa thuận đó (các loại hợp lệ) được thực hiện dễ dàng nhất bằng cách cơ sở dữ liệu thực thi nó với bảng 'enum'.).

2
@Voo việc sử dụng enum của Redmine giống như bugzilla "bảng quan trọng nhất chứa tất cả các lỗi của hệ thống. Nó được tạo thành từ các thuộc tính lỗi khác nhau bao gồm tất cả các giá trị enum như mức độ nghiêm trọng và mức độ ưu tiên." - Nó không phải là một trường văn bản biểu mẫu miễn phí, nó là một giá trị là một trong những tập hợp đã biết và vô số này. Nó không phải là một enum thời gian biên dịch , nhưng nó vẫn còn ghen tị. Xem thêm Thần chú .

1
Vì vậy, để xác nhận - quan điểm của bạn là mọi người không bao giờ nên sử dụng Enums? Không rõ ràng.
niico

18

Bạn nghĩ điều nào trong số này có khả năng gây ra lỗi khi đọc truy vấn?

select * 
from Person 
where Gender = 1

Hoặc là

select * 
from Person join Gender on Person.Gender = Gender.GenderId
where Gender.Label = "Female" 

Mọi người tạo các bảng enum trong SQL vì họ thấy cái sau dễ đọc hơn - dẫn đến việc viết và duy trì SQL ít hơn.

Bạn có thể biến giới tính thành một chuỗi trực tiếp Person, nhưng sau đó bạn sẽ phải thử và thi hành trường hợp. Bạn cũng có thể tăng lượt lưu trữ cho bảng và thời gian truy vấn do sự khác biệt giữa các chuỗi và số nguyên tùy thuộc vào mức độ tuyệt vời của DB của bạn trong việc tối ưu hóa mọi thứ.


5
Nhưng sau đó chúng tôi tham gia các bảng. Nếu thực thể của tôi có hai enum, tôi sẽ tham gia ba bảng chỉ cho một truy vấn đơn giản.
dùng3748908

11
@ user3748908 - vậy sao? Tham gia là những gì DB giỏi, và các lựa chọn thay thế tồi tệ hơn - ít nhất là trong mắt những người đã chọn con đường này.
Telastyn

8
@ user3748908: Không chỉ cơ sở dữ liệu thực sự tốt khi tham gia, chúng còn thực sự tốt trong việc thực thi tính nhất quán. Thực thi tính nhất quán hoạt động thực sự, thực sự tốt khi bạn có thể trỏ một cột trong một bảng vào hàng nhận dạng của người khác và nói "giá trị cho cột này phải là một trong những định danh trong bảng đó."
Blrfl

2
Điều này hoàn toàn đúng nhưng có nhiều trường hợp bạn cần phải hy sinh các liên kết vì lý do hiệu suất. Đừng hiểu lầm tôi là tất cả về kiểu thiết kế và tham gia này nhưng tôi cho rằng thế giới sẽ không kết thúc nếu bạn thấy bạn đôi khi không cần sự tham gia do hiệu suất.
JonH

3
Nếu bạn phải bỏ tham gia vào các bảng tham chiếu vì lý do hiệu suất @JonH, bạn cần mua một máy chủ lớn hơn hoặc ngừng cố gắng đẩy các vị từ thông qua số lượng lớn các truy vấn phụ (Tôi giả sử bạn biết bạn đang làm gì). Các bảng tham chiếu là những thứ nên có trong bộ đệm của bạn trong vài giây sau khi khởi động DB.
Bến

10

Tôi không thể tin rằng mọi người đã không đề cập đến điều này chưa.

Khóa ngoại

Bằng cách giữ enum trong cơ sở dữ liệu của bạn và thêm khóa ngoại trên bảng có chứa giá trị enum, bạn đảm bảo rằng không có mã nào nhập các giá trị không chính xác cho cột đó. Điều này giúp tính toàn vẹn dữ liệu của bạn và là lý do rõ ràng nhất IMO bạn nên có bảng cho enums.


Câu hỏi chỉ dài 5 dòng và ghi rõ "Bên cạnh lý do rõ ràng về việc thực thi tính đúng đắn". Vì vậy, không ai đề cập đến điều đó bởi vì OP tuyên bố rằng điều đó là hiển nhiên và anh ta đang tìm kiếm những lời biện minh khác - PS: Tôi đồng ý với bạn, đó là một lý do đủ tốt.
dùng1007074

6

Tôi ở trong trại đồng ý với bạn. Nếu bạn giữ một enum Giới tính trong mã của bạn và một tblGender trong cơ sở dữ liệu của bạn, bạn có thể gặp rắc rối trong thời gian bảo trì. Bạn sẽ cần phải ghi lại rằng hai thực thể này phải có cùng các giá trị và do đó, bất kỳ thay đổi nào bạn thực hiện đối với một thực thể bạn cũng phải thực hiện đối với đối tượng kia.

Sau đó, bạn sẽ cần chuyển các giá trị enum cho các thủ tục được lưu trữ của mình như sau:

create stored procedure InsertPerson @name varchar, @gender int
    insert into tblPeople (name, gender)
    values (@name, @gender)

Nhưng hãy nghĩ cách bạn làm điều này nếu bạn giữ các giá trị này trong bảng cơ sở dữ liệu:

create stored procedure InsertPerson @name varchar, @genderName varchar
    insert into tblPeople (name, gender)
    select @name, fkGender
    from tblGender
    where genderName = @genderName --I hope these are the same

Chắc chắn cơ sở dữ liệu quan hệ được xây dựng với các liên kết trong tâm trí, nhưng truy vấn nào dễ đọc hơn?


Đây là một truy vấn ví dụ khác:

create stored procedure SpGetGenderCounts
    select count(*) as count, gender
    from tblPeople
    group by gender

So sánh điều đó với điều này:

create stored procedure SpGetGenderCounts
    select count(*) as count, genderName
    from tblPeople
    inner join tblGender on pkGender = fkGender
    group by genderName --assuming no two genders have the same name

Đây là một truy vấn ví dụ khác:

create stored procedure GetAllPeople
    select name, gender
    from tblPeople

Lưu ý rằng trong ví dụ này, bạn phải chuyển đổi ô giới tính trong kết quả của mình từ int thành enum. Những chuyển đổi này là dễ dàng tuy nhiên. So sánh điều đó với điều này:

create stored procedure GetAllPeople
    select name, genderName
    from tblPeople
    inner join tblGender on pkGender = fkGender

Tất cả các truy vấn này nhỏ hơn và dễ bảo trì hơn khi đi với ý tưởng của bạn về việc giữ các định nghĩa enum ra khỏi cơ sở dữ liệu.


1
Điều gì xảy ra nếu đó không phải là giới tính. Tôi nghĩ rằng chúng ta đang quá nôn nao về giới là lĩnh vực. Điều gì sẽ xảy ra nếu OP đã nói "Vì vậy, hãy nói rằng tôi có Lỗi thực thể với trường Ưu tiên" - câu trả lời của bạn có thay đổi không?

4
@MichaelT Danh sách các giá trị có thể có của "mức độ ưu tiên" là một phần của mã ít nhất ở cùng mức độ là một phần của dữ liệu. Bạn có thấy các biểu tượng đồ họa cho các ưu tiên khác nhau? Bạn không mong đợi họ được rút khỏi cơ sở dữ liệu? Và những thứ như thế có thể theo chủ đề và được tạo kiểu và vẫn đại diện cho cùng một phạm vi giá trị được lưu trữ trong DB. Bạn không thể thay đổi nó trong cơ sở dữ liệu nào; bạn có mã trình bày để đồng bộ hóa.
Eugene Ryabtsev

1

Tôi sẽ tạo một bảng Giới tính với lý do nó có thể được sử dụng trong phân tích dữ liệu. Tôi có thể tra cứu tất cả những người Nam hoặc Nữ trong cơ sở dữ liệu để tạo báo cáo. Càng nhiều cách bạn có thể xem dữ liệu của mình, bạn càng dễ dàng khám phá thông tin xu hướng. Rõ ràng, đây là cách liệt kê rất đơn giản, nhưng đối với các bảng liệt kê phức tạp (như các quốc gia trên thế giới hoặc các tiểu bang), việc tạo ra các báo cáo chuyên ngành dễ dàng hơn.


1

Trước tiên, bạn cần phải quyết định xem cơ sở dữ liệu sẽ chỉ được sử dụng bởi một ứng dụng hay nếu có tiềm năng cho nhiều ứng dụng sử dụng nó. Trong một số trường hợp, cơ sở dữ liệu không có gì khác ngoài định dạng tệp cho một ứng dụng (cơ sở dữ liệu SQLite thường có thể được sử dụng trong vấn đề này). Trong trường hợp này, bit nhân đôi định nghĩa enum như một bảng thường có thể tốt và có thể có ý nghĩa hơn.

Tuy nhiên, ngay khi bạn muốn xem xét khả năng có nhiều ứng dụng truy cập cơ sở dữ liệu, thì một bảng cho enum có rất nhiều ý nghĩa (các câu trả lời khác đi vào lý do chi tiết hơn). Một điều khác cần xem xét là bạn hoặc nhà phát triển khác muốn xem xét dữ liệu cơ sở dữ liệu thô. Nếu vậy, đây có thể được coi là một ứng dụng khác sử dụng (chỉ một trong đó thước đo phòng thí nghiệm là SQL thô).

Nếu bạn có enum được xác định trong mã (để kiểm tra mã sạch hơn và kiểm tra thời gian biên dịch) cũng như một bảng trong cơ sở dữ liệu, tôi khuyên bạn nên thêm các kiểm tra đơn vị để xác minh rằng hai đồng bộ hóa.


1

Khi bạn có một bảng liệt kê mã được sử dụng để điều khiển logic nghiệp vụ trong mã, bạn vẫn nên tạo một bảng để biểu thị dữ liệu trong DB vì nhiều lý do chi tiết ở trên / dưới đây. Dưới đây là một số mẹo để đảm bảo rằng các giá trị DB của bạn được đồng bộ hóa với các giá trị mã:

  1. Không đặt trường ID trên bảng thành cột Danh tính. Bao gồm ID và Mô tả dưới dạng các trường.

  2. Làm một cái gì đó khác nhau trong bảng giúp các nhà phát triển biết rằng các giá trị là bán tĩnh / gắn với một bảng liệt kê mã. Trong tất cả các bảng tra cứu khác (thường là nơi người dùng có thể thêm các giá trị) Tôi thường có LastChangedDateTime và LastChangedBy, nhưng không có chúng trên các bảng liên quan đến enum giúp tôi nhớ rằng chúng chỉ có thể thay đổi bởi các nhà phát triển. Tài liệu này.

  3. Tạo mã xác minh để kiểm tra xem mỗi giá trị trong bảng liệt kê nằm trong bảng tương ứng và chỉ những giá trị đó nằm trong bảng tương ứng. Nếu bạn có ứng dụng tự động "kiểm tra sức khỏe" chạy sau xây dựng, tại đó. Nếu không, làm cho mã chạy tự động khi khởi động ứng dụng bất cứ khi nào ứng dụng đang chạy trong IDE.

  4. Tạo sản xuất cung cấp các tập lệnh SQL làm tương tự, nhưng từ bên trong DB. Nếu được tạo chính xác, chúng cũng sẽ giúp di chuyển môi trường.


0

Cũng phụ thuộc vào người truy cập dữ liệu. Nếu bạn chỉ có một ứng dụng có thể tốt. Nếu bạn thêm vào một kho dữ liệu hoặc một hệ thống báo cáo. Họ sẽ cần phải biết mã đó có nghĩa là gì, phiên bản mã có thể đổi được của con người là gì.

Thông thường, bảng loại sẽ không được sao chép dưới dạng enum trong mã. Bạn có thể tải bảng loại trong một danh sách được lưu trữ.

Class GenderList

   Public Shared Property UnfilteredList
   Public Shared Property Male = GetItem("M")
   Public Shared Property Female = GetItem("F")

End Class

Thông thường, loại đến và đi. Bạn sẽ cần một ngày khi loại mới được thêm vào. Biết khi nào một loại cụ thể đã được gỡ bỏ. Chỉ hiển thị khi cần thiết. Điều gì xảy ra nếu một khách hàng muốn "chuyển giới" là một giới tính nhưng các khách hàng khác thì không? Tất cả các thông tin này được lưu trữ tốt nhất trong cơ sở dữ liệu.

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.