Cái nào hiệu quả hơn: Nhiều bảng MySQL hay một bảng lớn?


103

Tôi lưu trữ các chi tiết người dùng khác nhau trong cơ sở dữ liệu MySQL của mình. Ban đầu nó được thiết lập trong các bảng khác nhau có nghĩa là dữ liệu được liên kết với UserIds và xuất ra thông qua các cuộc gọi đôi khi phức tạp để hiển thị và thao tác dữ liệu theo yêu cầu. Thiết lập một hệ thống mới, gần như hợp lý khi kết hợp tất cả các bảng này thành một bảng lớn có nội dung liên quan.

  • Điều này sẽ là một sự trợ giúp hay trở ngại?
  • Cân nhắc tốc độ khi gọi, cập nhật hoặc tìm kiếm / thao tác?

Đây là một ví dụ về một số (các) cấu trúc bảng của tôi:

  • người dùng - UserId, tên người dùng, email, mật khẩu được mã hóa, ngày đăng ký, ip
  • user_details - dữ liệu cookie, tên, địa chỉ, chi tiết liên hệ, chi nhánh, dữ liệu nhân khẩu học
  • user_activity - đóng góp, lần trực tuyến cuối cùng, lần xem cuối cùng
  • user_settings - cài đặt hiển thị hồ sơ
  • user_interests - các biến có thể nhắm mục tiêu quảng cáo
  • user_levels - quyền truy cập
  • user_stats - lượt truy cập, dấu hiệu

Chỉnh sửa: Tôi đã ủng hộ tất cả các câu trả lời cho đến nay, tất cả chúng đều có các yếu tố về cơ bản trả lời câu hỏi của tôi.

Hầu hết các bảng có mối quan hệ 1: 1, đó là lý do chính khiến chúng không chuẩn hóa.

Sẽ có vấn đề gì xảy ra nếu bảng kéo dài qua hơn 100 cột khi một phần lớn các ô này có khả năng vẫn trống?


Đây câu hỏi khác có thể hữu ích quá
Mosty Mostacho

Câu trả lời:


65

Nhiều bảng trợ giúp trong những cách / trường hợp sau:

(a) nếu những người khác nhau sẽ phát triển các ứng dụng liên quan đến các bảng khác nhau, thì nên chia chúng ra.

(b) Nếu bạn muốn trao các loại thẩm quyền khác nhau cho những người khác nhau để thực hiện các phần khác nhau của việc thu thập dữ liệu, thì việc chia nhỏ chúng có thể thuận tiện hơn. (Tất nhiên, bạn có thể xem xét việc xác định các quan điểm và ủy quyền cho chúng một cách thích hợp).

(c) Để di chuyển dữ liệu đến những nơi khác nhau, đặc biệt là trong quá trình phát triển, có thể hợp lý khi sử dụng các bảng dẫn đến kích thước tệp nhỏ hơn.

(d) Dấu chân nhỏ hơn có thể mang lại sự thoải mái trong khi bạn phát triển các ứng dụng về thu thập dữ liệu cụ thể của một thực thể.

(e) Đó là một khả năng: những gì bạn nghĩ là một dữ liệu giá trị đơn lẻ có thể thực sự là nhiều giá trị trong tương lai. ví dụ hạn mức tín dụng là một trường giá trị duy nhất cho đến nay. Nhưng ngày mai, bạn có thể quyết định thay đổi các giá trị như (ngày từ, ngày thành, giá trị tín dụng). Bảng chia có thể trở nên hữu ích ngay bây giờ.

Phiếu bầu của tôi sẽ dành cho nhiều bảng - với dữ liệu được phân chia thích hợp.

Chúc may mắn.


3
@RohitKhatri: Theo hiểu biết của tôi, có nhiều bảng sẽ tăng hiệu suất trong hầu hết các trường hợp.
Hari Harker

1
@HariHarker Cảm ơn câu trả lời của bạn, nhưng tôi nhận ra rằng Điều đó phụ thuộc vào kiểu truy cập của bạn.
Rohit Khatri

Cho đến gần đây, tôi luôn lưu trữ tất cả dữ liệu trong một bảng, nhưng hãy nghĩ lại, nó có rất nhiều lợi thế khi phân chia dữ liệu về hiệu suất (tùy thuộc vào trường hợp sử dụng), ngữ nghĩa (một số dữ liệu được nhóm tốt hơn trong một bảng khác nhau) và sự phát triển. Ví dụ, tôi đang phát triển một hệ thống ERP tùy chỉnh ngay bây giờ trên hệ thống cũ. Tôi đã phải mở rộng các bảng cơ sở dữ liệu cũ với các cột bổ sung. Tôi quyết định tạo bảng mới cho dữ liệu mới. Một số tính năng mới có ích cho hệ thống cũ và bây giờ tôi có thể dễ dàng tích hợp chúng mà không cần phải viết lại quá nhiều của các truy vấn cũ
Ogier Schelvis

35

Kết hợp các bảng được gọi là không chuẩn hóa.

Có thể (hoặc có thể không) giúp một số truy vấn (tạo ra nhiều truy vấn JOIN) chạy nhanh hơn với chi phí tạo ra một địa ngục bảo trì.

MySQLcó khả năng sử dụng JOINphương pháp duy nhất , cụ thể là NESTED LOOPS.

Điều này có nghĩa là đối với mỗi bản ghi trong bảng điều khiển, MySQLđịnh vị một bản ghi phù hợp trong bảng điều khiển trong một vòng lặp.

Xác định vị trí một bản ghi là một hoạt động khá tốn kém, có thể mất hàng chục lần so với việc quét bản ghi thuần túy.

Di chuyển tất cả các bản ghi của bạn vào một bảng sẽ giúp bạn loại bỏ thao tác này, nhưng bản thân bảng sẽ lớn hơn và quá trình quét bảng mất nhiều thời gian hơn.

Nếu bạn có nhiều bản ghi trong các bảng khác, thì việc tăng số lần quét bảng có thể làm tăng lợi ích của các bản ghi được quét tuần tự.

Mặt khác, địa ngục bảo trì được đảm bảo.


1
Nếu bạn có 10000 người dùng và bạn đang tham gia với một cơ sở dữ liệu được thiết lập chính xác bằng các khóa ngoại thì bạn chỉ cần tra cứu dữ dội bằng cách thực hiện một số thao tác như select * từ những người dùng mà name = "bob". Khi bạn đã có bob thì bạn đang sử dụng một chỉ mục để tìm các bảng đã nối với bob, việc này nhanh hơn đáng kể vì bạn đang sử dụng id của bob. Điều này xảy ra bất kể bạn đang thực hiện kết hợp trong truy vấn của mình hay bob truy vấn rồi truy vấn một bảng riêng biệt. Tất nhiên, hy vọng rằng truy vấn thứ hai của bạn dựa trên id của bob chứ không phải thứ gì khác.
Rudy Garcia,

17

Tất cả chúng có phải là mối quan hệ 1: 1 không? Ý tôi là, nếu một người dùng có thể thuộc, chẳng hạn, các cấp độ người dùng khác nhau hoặc nếu sở thích của người dùng được thể hiện dưới dạng một số bản ghi trong bảng sở thích của người dùng, thì việc hợp nhất các bảng đó sẽ không có vấn đề gì ngay lập tức.

Liên quan đến các câu trả lời trước đây về chuẩn hóa, phải nói rằng các quy tắc chuẩn hóa cơ sở dữ liệu đã hoàn toàn bỏ qua hiệu suất và chỉ xem xét thiết kế cơ sở dữ liệu gọn gàng là gì. Đó thường là những gì bạn muốn đạt được, nhưng đôi khi bạn nên chủ động không chuẩn hóa để theo đuổi hiệu suất.

Tựu chung lại, tôi muốn nói câu hỏi đặt ra là có bao nhiêu trường trong các bảng và tần suất chúng được truy cập. Nếu hoạt động của người dùng thường không thú vị lắm, thì có thể sẽ gây phiền toái khi luôn có nó trong cùng một bản ghi, vì lý do hiệu suất bảo trì. Nếu một số dữ liệu, chẳng hạn như cài đặt, chẳng hạn, được truy cập rất thường xuyên, nhưng chỉ chứa quá nhiều trường, thì việc hợp nhất các bảng cũng có thể không thuận tiện. Nếu bạn chỉ quan tâm đến mức tăng hiệu suất, bạn có thể xem xét các cách tiếp cận khác, chẳng hạn như giữ các cài đặt riêng biệt, nhưng lưu chúng trong một biến phiên của riêng chúng để bạn không phải truy vấn cơ sở dữ liệu cho chúng thường xuyên.


Tôi phải hoàn toàn không đồng ý với nhận xét của bạn rằng bình thường hóa chỉ tập trung vào sự gọn gàng và hoàn toàn không quan tâm đến hiệu suất. Có một sự đánh đổi trong cả hai tình huống và việc không chuẩn hóa thực sự khiến tính toàn vẹn của dữ liệu gặp rủi ro. Tôi muốn nói rằng việc chuẩn hóa cơ sở dữ liệu của bạn thực sự cải thiện hiệu suất tổng thể của cơ sở dữ liệu hơn là làm tăng hiệu suất nhanh chóng không đáng kể từ một bảng không chuẩn hóa.
Rudy Garcia

Cho rằng cuộc thảo luận đặc biệt là về mối quan hệ 1: 1, việc tách các bảng không phải là một nhiệm vụ chuẩn hóa , phải không? Nếu không có thông tin trùng lặp, nó bình thường ngay cả khi nó là một bảng duy nhất. (Vâng, nó có thể không đáp ứng 3NFbình thường, vì vậy lợi ích từ một bảng thứ hai để giải quyết đó, nhưng điều đó dường như không có gì OP là đề cập đến lại các bảng khác.)
ToolmakerSteve

14

Làm tất cả những bảng có một 1-to-1mối quan hệ? Ví dụ: mỗi hàng người dùng sẽ chỉ có một hàng tương ứng trong user_statshoặc user_levels? Nếu vậy, có thể hợp lý khi kết hợp chúng thành một bảng. Nếu không có mối quan hệ 1 to 1, có lẽ sẽ không hợp lý khi kết hợp (không chuẩn hóa) chúng.

Có chúng trong các bảng riêng biệt so với một bảng có lẽ sẽ ít ảnh hưởng đến hiệu suất, trừ khi bạn có hàng trăm nghìn hoặc hàng triệu bản ghi người dùng. Lợi ích thực sự duy nhất bạn sẽ nhận được là từ việc đơn giản hóa các truy vấn của mình bằng cách kết hợp chúng.

ETA:

Nếu mối quan tâm của bạn là về việc có quá nhiều cột , thì hãy nghĩ đến những thứ bạn thường sử dụng cùng nhau và kết hợp chúng , để phần còn lại trong một bảng riêng biệt (hoặc một số bảng riêng biệt nếu cần).

Nếu bạn nhìn vào cách bạn sử dụng dữ liệu, tôi đoán rằng bạn sẽ thấy rằng 80% truy vấn của bạn sử dụng 20% ​​dữ liệu đó với 80% dữ liệu còn lại chỉ thỉnh thoảng được sử dụng. Kết hợp 20% thường xuyên sử dụng vào một bảng và để lại 80% mà bạn không thường sử dụng trong các bảng riêng biệt và có thể bạn sẽ có một sự thỏa hiệp tốt.


Có mỗi bảng chỉ có 1 hàng cho mỗi người dùng, đơn giản để đỡ đau đầu quản lý nhiều dữ liệu trùng lặp. Đây là lý do tại sao tôi đang nghĩ một chiếc bàn phù hợp. Nếu dữ liệu người dùng kéo dài nhiều hàng, tôi sẽ mong đợi các bảng đó được tách khỏi bảng người dùng chính.
Peter Craig,

1
Nếu mọi bảng có mối quan hệ từ 1 đến 1 thì một bảng sẽ dễ sử dụng hơn. Không cần thiết phải chia bảng trong trường hợp đó. Việc chia nhỏ bảng sẽ khiến có nhiều hơn 1 hàng, điều này có thể dẫn đến trường hợp nhà phát triển khác sẽ xử lý chúng theo cách đó.
Richard L

Ý nghĩ rất thú vị khi áp dụng 80/20 vào thiết kế bảng cơ sở dữ liệu. Tôi cũng nghĩ về thiết kế lớp OOP (tôi chủ yếu là nhà phát triển Java) và tự hỏi liệu điều tương tự có thể hiệu quả ở đó hay không (đặt 80% chức năng ứng dụng chính vào một lớp và phần còn lại trong các lớp khác).
Zack Macomber

1
@ZackMacomber - Không, việc tách lớp phải dựa trên vị trí tham chiếu . Lợi ích của việc chia thành nhiều lớp là vẽ đường viền xung quanh một đơn vị chức năng nhỏ hơn, để dễ hiểu / kiểm tra / thay đổi hơn và rõ ràng nơi đơn vị đó tương tác với các đơn vị chức năng khác. Mục đích là giữ hầu hết các kết nối (tham chiếu, cuộc gọi) bên trong một đơn vị, với ít kết nối giữa các đơn vị . Định nghĩa một số giao diện mà lớp thực hiện, với giao diện khác nhau cho mỗi trường hợp sử dụng, có thể là bước đầu tiên hữu ích đối với việc phân tách đó.
ToolmakerSteve

@ToolmakerSteve Suy nghĩ tốt +1
Zack Macomber

9

Tạo một bảng lớn đi ngược lại với các nguyên tắc cơ sở dữ liệu quan hệ. Tôi sẽ không kết hợp tất cả chúng vào một bảng. Bạn sẽ nhận được nhiều trường hợp dữ liệu lặp lại. Ví dụ: nếu người dùng của bạn có ba sở thích, bạn sẽ có 3 hàng, với cùng một dữ liệu người dùng chỉ để lưu trữ ba sở thích khác nhau. Chắc chắn hãy sử dụng phương pháp nhiều bảng 'chuẩn hóa'. Xem trang Wiki này để chuẩn hóa cơ sở dữ liệu.

Chỉnh sửa: Tôi đã cập nhật câu trả lời của mình, vì bạn đã cập nhật câu hỏi của mình ... Tôi đồng ý với câu trả lời ban đầu của mình hơn nữa kể từ bây giờ ...

một phần lớn các ô này có khả năng vẫn trống

Ví dụ: nếu một người dùng không có bất kỳ sở thích nào, nếu bạn chuẩn hóa thì đơn giản là bạn sẽ không có hàng trong bảng sở thích cho người dùng đó. Nếu bạn có mọi thứ trong một bảng lớn, thì bạn sẽ có các cột (và dường như rất nhiều trong số chúng) chỉ chứa NULL.

Tôi đã từng làm việc cho một công ty điện thoại, nơi có rất nhiều bảng, việc lấy dữ liệu có thể yêu cầu nhiều sự tham gia. Khi hiệu suất đọc từ các bảng này là quan trọng thì các thủ tục nơi được tạo có thể tạo ra một bảng phẳng (tức là một bảng không chuẩn hóa) sẽ không yêu cầu các phép nối, phép tính, v.v. mà các báo cáo có thể trỏ đến. Những nơi này sau đó được sử dụng kết hợp với tác nhân máy chủ SQL để chạy công việc theo những khoảng thời gian nhất định (tức là chế độ xem hàng tuần của một số thống kê sẽ chạy mỗi tuần một lần, v.v.).


Tôi thích cách tiếp cận này, bởi vì dữ liệu không chuẩn hóa chỉ tồn tại tạm thời, dưới dạng ảnh chụp nhanh của một thời điểm. Không có vấn đề chèn / sửa đổi / xóa - chỉ cần ném nó đi khi hoàn tất.
ToolmakerSteve

7

Tại sao không sử dụng cách tiếp cận tương tự Wordpress làm bằng cách có một bảng người dùng với thông tin người dùng cơ bản mà mọi người đều có và sau đó thêm một bảng "user_meta" về cơ bản có thể là bất kỳ cặp khóa, giá trị nào được liên kết với id người dùng. Vì vậy, nếu bạn cần tìm tất cả thông tin meta cho người dùng, bạn chỉ cần thêm thông tin đó vào truy vấn của mình. Bạn cũng không phải lúc nào cũng phải thêm truy vấn bổ sung nếu không cần thiết cho những việc như đăng nhập. Lợi ích của cách tiếp cận này cũng khiến bảng của bạn mở để thêm các tính năng mới cho người dùng của bạn như lưu trữ tay cầm twitter của họ hoặc từng sở thích riêng lẻ. Bạn cũng sẽ không phải đối mặt với một mê cung gồm các ID được liên kết bởi vì bạn có một bảng quy định tất cả siêu dữ liệu và bạn sẽ giới hạn nó chỉ ở một liên kết thay vì 50.

Wordpress đặc biệt làm điều này để cho phép các tính năng được thêm vào thông qua plugin, do đó cho phép dự án của bạn có thể mở rộng hơn và sẽ không yêu cầu đại tu cơ sở dữ liệu hoàn chỉnh nếu bạn cần thêm một tính năng mới.


Bảng Wordpress wp_usermetaphát triển về mặt hình học. Mỗi người dùng thêm X hàng vào wp_usermetabảng, một hàng cho mỗi phần thông tin meta mà chúng tôi muốn giữ cho người dùng đó. Nếu bạn giữ 8 trường tùy chỉnh cho mỗi người dùng, điều đó có nghĩa là wp_usermeta sẽ users * 8dài hàng. Điều này dường như đang gây ra các vấn đề về hiệu suất, nhưng tôi không chắc đó có phải là sự cố hay không…
thirdender

1
Tôi có thể thấy điều này có thể gây ra các vấn đề về hiệu suất như thế nào nếu bạn có hàng chục nghìn người dùng. Về cơ bản, cơ sở dữ liệu sẽ phải tìm kiếm qua 10000 * 8 mục nhập trong bảng meta người dùng để tìm những mục bạn đang tìm kiếm. Tuy nhiên, nếu bạn chỉ truy vấn dữ liệu Meta khi cần, tôi nghĩ rằng hiệu suất của bạn sẽ tốt hơn. Nếu bạn luôn yêu cầu dữ liệu meta ngay cả khi bạn không cần nó thì bạn có thể gặp vấn đề. Nếu bạn luôn cần dữ liệu meta thì có thể chia nhỏ các bảng không phải là cách tốt nhất.
Rudy Garcia

1
Mới hôm qua, chúng tôi đã xử lý một chủ đề WP đang tải tất cả người dùng (đang sử dụng get_users()) chỉ để tính toán phân trang. Sau khi chúng tôi sửa mã để sử dụng SELECT COUNT(…)truy vấn cho phân trang thay vào đó, thời gian tải trang đã tăng từ 28 giây xuống còn khoảng 400 mili giây. Tôi vẫn băn khoăn không biết hiệu suất như thế nào so với các bảng được kết hợp hoặc một bảng phẳng duy nhất… Tôi đã gặp khó khăn khi tìm bất kỳ số liệu hiệu suất nào trên web.
thirdender

Suy nghĩ về nhận xét trước đây của tôi, có vẻ như việc tách bảng vẫn hiệu quả trừ khi vì một lý do nào đó, chẳng hạn như ví dụ về phân trang ở trên, bạn cần phải chọn tất cả người dùng. Mặc dù nếu bạn đang truy xuất tất cả thông tin meta, bạn vẫn sẽ có 80 nghìn mục nhập trong bảng usermeta. Đó là rất nhiều để tìm kiếm thông qua. Có lẽ ai đó có thể kiểm tra đâu là cách tiếp cận tốt hơn bằng cách chạy một tập lệnh trên cả hai triển khai và chạy nó 100 lần để lấy mức trung bình, tôi có thể chỉ làm điều đó.
Rudy Garcia

1
Tôi đã đọc lại điều này ngay hôm nay và nhận ra rằng nhận xét của tôi về 10000 * 8 mục nhập là đúng, tuy nhiên cách hoạt động của cơ sở dữ liệu sẽ khiến nó hầu như không phải là vấn đề. Nếu vì lý do nào đó mà bạn thu hút tất cả 10000 người dùng VÀ cả thông tin meta của họ thì điều này sẽ thật nực cười. Tôi không thể nghĩ ra bất kỳ kịch bản nào mà bạn muốn điều này. Cơ sở dữ liệu sẽ dễ dàng truy xuất meta cho một người dùng với tốc độ cực nhanh mặc dù vì các khóa ngoại và lập chỉ mục. Giả sử mô hình db của bạn được thiết lập chính xác.
Rudy Garcia

5

Tôi nghĩ đây là một trong những tình huống "nó phụ thuộc". Có nhiều bảng thì rõ ràng hơn và có lẽ tốt hơn về mặt lý thuyết. Nhưng khi bạn phải tham gia 6-7 bảng để có thông tin về một người dùng, bạn có thể bắt đầu suy nghĩ lại về cách tiếp cận đó.


1

Tôi sẽ nói rằng nó phụ thuộc vào những gì các bảng khác thực sự có ý nghĩa. Một user_details có chứa nhiều hơn 1 / người dùng khác, v.v. Mức độ chuẩn hóa phù hợp nhất với nhu cầu của bạn tùy thuộc vào nhu cầu của bạn.

Nếu bạn có một bảng với chỉ số tốt có thể sẽ nhanh hơn. Nhưng mặt khác có lẽ khó bảo trì hơn.

Đối với tôi, có vẻ như bạn có thể bỏ qua User_Details vì nó có thể là mối quan hệ 1-1 với Người dùng. Nhưng phần còn lại có lẽ là rất nhiều hàng cho mỗi người dùng?

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.