Có lý do gì để lo lắng về thứ tự cột trong bảng?


84

Tôi biết bạn có thể thay đổi thứ tự cột trong MySQL với FIRST và SAU, nhưng tại sao bạn lại muốn làm phiền? Vì các truy vấn tốt đặt tên rõ ràng cho các cột khi chèn dữ liệu, thực sự có lý do gì để quan tâm đến thứ tự các cột của bạn trong bảng?

Câu trả lời:


94

Thứ tự cột có tác động lớn đến hiệu suất trên một số cơ sở dữ liệu mà tôi đã điều chỉnh, bao gồm cả Sql Server, Oracle và MySQL. Bài đăng này có các quy tắc ngón tay cái tốt :

  • Các cột khóa chính đầu tiên
  • Các cột khóa ngoại tiếp theo.
  • Các cột được tìm kiếm thường xuyên tiếp theo
  • Các cột được cập nhật thường xuyên sau này
  • Các cột có thể vô hiệu hóa cuối cùng.
  • Các cột có thể không sử dụng ít nhất sau các cột có thể không sử dụng thường xuyên hơn

Một ví dụ cho sự khác biệt về hiệu suất là tra cứu Chỉ mục. Công cụ cơ sở dữ liệu tìm một hàng dựa trên một số điều kiện trong chỉ mục và lấy lại địa chỉ hàng. Bây giờ giả sử bạn đang tìm kiếm SomeValue và nó nằm trong bảng sau:

 SomeId int,
 SomeString varchar(100),
 SomeValue int

Công cụ phải đoán nơi SomeValue bắt đầu, vì SomeString có độ dài không xác định. Tuy nhiên, nếu bạn thay đổi thứ tự thành:

 SomeId int,
 SomeValue int,
 SomeString varchar(100)

Bây giờ công cụ biết rằng SomeValue có thể được tìm thấy 4 byte sau khi bắt đầu hàng. Vì vậy, thứ tự cột có thể có tác động đáng kể đến hiệu suất.

CHỈNH SỬA: Sql Server 2005 lưu trữ các trường có độ dài cố định ở đầu hàng. Và mỗi hàng có một tham chiếu đến phần đầu của một varchar. Điều này hoàn toàn phủ nhận hiệu ứng mà tôi đã liệt kê ở trên. Vì vậy, đối với các cơ sở dữ liệu gần đây, thứ tự cột không còn có bất kỳ tác động nào nữa.


4
@TopBanana: không phải với varchars, đó là những gì phân biệt chúng với các cột char bình thường.
Allain Lalonde

1
Tôi không nghĩ thứ tự của các cột TRONG BẢNG tạo ra bất kỳ sự khác biệt nào - nó chắc chắn tạo ra sự khác biệt trong CHỈ SỐ mà bạn có thể tạo, đúng.
marc_s

4
@TopBanana: không chắc bạn có biết Oracle hay không, nhưng nó không dành 100 byte cho VARCHAR2 (100)
Quassnoi

1
@Quassnoi: tác động lớn nhất là trên Sql Server, trên một bảng có nhiều cột varchar () nullable.
Andomar

7
URL trong câu trả lời này không còn hoạt động nữa, có ai có URL thay thế không?
scunliffe

41

Cập nhật:

Trong MySQL, có thể có một lý do để làm điều này.

Vì các kiểu dữ liệu biến (như VARCHAR) được lưu trữ với độ dài thay đổi trong InnoDB, công cụ cơ sở dữ liệu phải duyệt qua tất cả các cột trước đó trong mỗi hàng để tìm ra phần bù của hàng đã cho.

Tác động có thể lớn tới 17% đối với 20các cột.

Xem mục này trong blog của tôi để biết thêm chi tiết:

Trong Oracle, NULLcác cột theo sau không tốn không gian, đó là lý do tại sao bạn nên đặt chúng ở cuối bảng.

Cũng trong OracleSQL Server, trong trường hợp của một hàng lớn, ROW CHAININGcó thể xảy ra.

ROW CHANING là tách một hàng không vừa với một khối và kéo dài nó qua nhiều khối, được kết nối với một danh sách được liên kết.

Việc đọc các cột theo sau không vừa với khối đầu tiên sẽ yêu cầu duyệt qua danh sách được liên kết, điều này sẽ dẫn đến một I/Othao tác bổ sung .

Xem trang này để minh họa ROW CHAININGtrong Oracle:

Đó là lý do tại sao bạn nên đặt các cột bạn thường sử dụng ở đầu bảng và các cột bạn không sử dụng thường xuyên, hoặc các cột có xu hướng NULL, ở cuối bảng.

Lưu ý quan trọng:

Nếu bạn thích câu trả lời này và muốn bình chọn cho nó, vui lòng bình chọn cho @Andomarcâu trả lời của .

Anh ấy trả lời tương tự, nhưng dường như không có lý do gì.


1
Vì vậy, bạn đang nói rằng điều này sẽ chậm: chọn tinyTable.id, tblBIG.firstColumn, tblBIG.lastColumn từ tinyTable bên trong tham gia tblBIG trên tinyTable.id = tblBIG.fkID Nếu bản ghi tblBIG trên 8KB (trong trường hợp đó, một số chuỗi liên kết sẽ xảy ra ) và tham gia sẽ đồng bộ ... Nhưng điều này sẽ nhanh chóng: chọn tinyTable.id, tblBIG.firstColumn từ tinyTable bên trong tham gia tblBIG trên tinyTable.id = tblBIG.fkID Vì tôi sẽ không sử dụng cột trong các khối khác do đó không cần xem qua danh sách liên kết Tôi đã hiểu đúng chưa?
jfrobishow

1
Tôi chỉ nhận được 6% và đó là cho cột col1 so với bất kỳ cột nào khác.
Rick James

6

Trong quá trình đào tạo Oracle tại công việc trước đây, DBA của chúng tôi đã gợi ý rằng việc đặt tất cả các cột không thể nullable trước những cột có thể nullable là một lợi thế ... mặc dù TBH tôi không nhớ chi tiết tại sao. Hoặc có lẽ nó chỉ là những thứ có khả năng được cập nhật nên đi vào cuối? (Có thể tạm dừng việc phải di chuyển hàng nếu nó mở rộng)

Nói chung, nó không tạo ra bất kỳ sự khác biệt nào. Như bạn nói, các truy vấn phải luôn chỉ định chính các cột thay vì dựa vào thứ tự từ "select *". Tôi không biết bất kỳ DB nào cho phép thay đổi chúng ... tốt, tôi không biết MySQL cho phép điều đó cho đến khi bạn đề cập đến nó.


4
Ông ấy đã đúng, Oracle không ghi các cột NULL vào đĩa, tiết kiệm một số byte. Xem dba-oracle.com/oracle_tips_ault_nulls_values.htm
Andomar

hoàn toàn, nó có thể tạo ra sự khác biệt lớn về kích thước trên đĩa
Alex

Đó có phải là liên kết bạn muốn nói? Nó liên quan đến việc không lập chỉ mục của null trong các chỉ số hơn là thứ tự cột.
araqnid

Liên kết sai và không thể tìm thấy bản gốc. Mặc dù bạn có thể google để tìm nó, ví dụ: tlingua.com/new/articles/Chapter2.html
Andomar

5

Một số ứng dụng viết sai có thể phụ thuộc vào thứ tự cột / chỉ mục thay vì tên cột. Họ không nên như vậy, nhưng nó xảy ra. Thay đổi thứ tự của các cột sẽ phá vỡ các ứng dụng như vậy.


3
Các nhà phát triển ứng dụng làm cho mã của họ phụ thuộc vào thứ tự cột trong bảng DESERVE để ứng dụng của họ bị hỏng. Nhưng người dùng của ứng dụng không đáng bị ngừng hoạt động.
spencer7593

4

Khả năng đọc của đầu ra khi bạn phải nhập:

select * from <table>

trong phần mềm quản lý cơ sở dữ liệu của bạn?

Đó là một lý do rất giả, nhưng hiện tại tôi không thể nghĩ ra được điều gì khác.


4

Không, thứ tự của các cột trong bảng cơ sở dữ liệu SQL hoàn toàn không liên quan - ngoại trừ mục đích hiển thị / in ấn. Sắp xếp lại các cột chẳng có ích gì - hầu hết các hệ thống thậm chí không cung cấp cách để làm điều đó (ngoại trừ việc bỏ bảng cũ và tạo lại nó với thứ tự cột mới).

Marc

CHỈNH SỬA: từ mục nhập Wikipedia trên cơ sở dữ liệu quan hệ, đây là phần có liên quan mà tôi cho thấy rõ ràng rằng thứ tự cột không bao giờ nên quan tâm:

Một quan hệ được định nghĩa là một tập hợp n bộ giá trị. Trong cả toán học và mô hình cơ sở dữ liệu quan hệ, một tập hợp là một tập hợp các mục không có thứ tự , mặc dù một số DBMS áp đặt thứ tự cho dữ liệu của chúng. Trong toán học, một bộ giá trị có một thứ tự, và cho phép nhân đôi. EF Codd ban đầu đã xác định các bộ giá trị bằng cách sử dụng định nghĩa toán học này. Sau đó, một trong những hiểu biết tuyệt vời của EF Codd là việc sử dụng tên thuộc tính thay vì thứ tự sẽ thuận tiện hơn rất nhiều (nói chung) trong một ngôn ngữ máy tính dựa trên quan hệ. Cái nhìn sâu sắc này vẫn đang được sử dụng cho đến ngày nay.


1
Tôi đã tận mắt chứng kiến ​​sự khác biệt về cột có tác động lớn, vì vậy tôi không thể tin rằng đây là câu trả lời đúng. Mặc dù biểu quyết đặt nó lên hàng đầu. Hrm.
Andomar

Môi trường SQL nào sẽ ở trong đó?
marc_s

1
Tác động lớn nhất mà tôi đã thấy là trên Sql Server 2000, nơi việc di chuyển khóa ngoại về phía trước đã tăng tốc một số truy vấn lên 2 đến 3 lần. Những truy vấn đó đã quét bảng lớn (1 triệu hàng +) với một điều kiện về khóa ngoại.
Andomar

5
RDBMS không phụ thuộc vào thứ tự bảng trừ khi bạn quan tâm đến hiệu suất . Các triển khai khác nhau sẽ có các hình phạt hiệu suất khác nhau đối với thứ tự của các cột. Nó có thể rất lớn hoặc nó có thể nhỏ, nó phụ thuộc vào việc thực hiện. Tuples là lý thuyết, RDBMS là thực tế.
Esteban Küber

3
-1. Tất cả các cơ sở dữ liệu quan hệ mà tôi đã sử dụng DO có thứ tự cột ở một số cấp độ. Nếu bạn chọn * từ một bảng, bạn không có xu hướng lấy lại các cột theo thứ tự ngẫu nhiên. Bây giờ trên đĩa và hiển thị là một cuộc tranh luận khác nhau. Và việc trích dẫn lý thuyết toán học để sao lưu một giả định về việc triển khai thực tế cơ sở dữ liệu chỉ là một điều vô nghĩa.
DougW

2

Lý do duy nhất tôi có thể nghĩ đến là để gỡ lỗi và chữa cháy. Chúng tôi có một bảng có cột "tên" xuất hiện khoảng thứ 10 trong danh sách. Thật khó khăn khi bạn chọn nhanh * từ bảng có id trong (1,2,3) và sau đó bạn phải cuộn qua để xem tên.

Nhưng đó là về nó.


1

Như thường lệ, yếu tố lớn nhất là người tiếp theo phải làm việc trên hệ thống. Tôi cố gắng đặt các cột khóa chính trước tiên, các cột khóa ngoại thứ hai, rồi đến các cột còn lại theo thứ tự giảm dần về mức độ quan trọng / ý nghĩa đối với hệ thống.


Chúng tôi thường bắt đầu với cột cuối cùng được "tạo" (dấu thời gian cho thời điểm hàng được chèn). Tất nhiên, với các bảng cũ hơn, nó có thể có một số cột được thêm vào sau đó ... Và chúng ta có một bảng không thường xuyên trong đó khóa chính ghép được thay đổi thành khóa thay thế nên khóa chính sẽ kết thúc một số cột.
araqnid

1

Nếu bạn đang sử dụng UNION nhiều, thì việc so khớp các cột dễ dàng hơn nếu bạn có quy ước về thứ tự của chúng.


Có vẻ như cơ sở dữ liệu của bạn cần chuẩn hóa! :)
James L

Chào! Lấy lại, tôi không nói cơ sở dữ liệu của tôi. :)
Allain Lalonde


bạn có thể UNION với thứ tự các cột trong 2 bảng có thứ tự khác nhau không?
Monica Heddneck

Có, bạn chỉ cần chỉ định các cột một cách rõ ràng khi truy vấn các bảng. Với các bảng A [a, b] B [b, a], điều đó có nghĩa là (CHỌN aa, ab TỪ A) ĐOÀN KẾT (CHỌN ba, B ĐOÀN KẾT TỪ B) thay cho (CHỌN * TỪ A) ĐOÀN KẾT (CHỌN * TỪ B).
Allain Lalonde

1

Như đã lưu ý, có rất nhiều vấn đề về hiệu suất tiềm ẩn. Tôi đã từng làm việc trên một cơ sở dữ liệu nơi đặt các cột rất lớn ở cuối đã cải thiện hiệu suất nếu bạn không tham chiếu các cột đó trong truy vấn của mình. Rõ ràng nếu một bản ghi kéo dài nhiều khối đĩa, công cụ cơ sở dữ liệu có thể ngừng đọc các khối khi nó có tất cả các cột mà nó cần.

Tất nhiên, mọi tác động về hiệu suất không chỉ phụ thuộc nhiều vào nhà sản xuất mà bạn đang sử dụng mà còn phụ thuộc vào phiên bản. Một vài tháng trước, tôi nhận thấy rằng Postgres của chúng tôi không thể sử dụng một chỉ mục để so sánh "like". Có nghĩa là, nếu bạn viết "cột nào đó như 'M%'", sẽ không đủ thông minh để bỏ qua chữ M và bỏ qua khi nó tìm thấy chữ N. đầu tiên. Tôi đã định thay đổi một loạt các truy vấn để sử dụng "giữa". Sau đó, chúng tôi có một phiên bản Postgres mới và nó xử lý những thứ tương tự một cách thông minh. Rất vui vì tôi chưa bao giờ phải thay đổi các truy vấn. Rõ ràng là không liên quan trực tiếp ở đây nhưng quan điểm của tôi là bất cứ điều gì bạn làm để cân nhắc hiệu quả đều có thể lỗi thời với phiên bản tiếp theo.

Thứ tự cột hầu như luôn rất phù hợp với tôi vì tôi thường viết mã chung để đọc lược đồ cơ sở dữ liệu để tạo màn hình. Giống như, màn hình "chỉnh sửa bản ghi" của tôi hầu như luôn được xây dựng bằng cách đọc lược đồ để lấy danh sách các trường, sau đó hiển thị chúng theo thứ tự. Nếu tôi thay đổi thứ tự của các cột, chương trình của tôi sẽ vẫn hoạt động, nhưng hiển thị có thể lạ đối với người dùng. Giống như, bạn sẽ thấy tên / địa chỉ / thành phố / tiểu bang / zip, không phải thành phố / địa chỉ / zip / tên / tiểu bang. Chắc chắn, tôi có thể đặt thứ tự hiển thị của các cột trong mã hoặc tệp điều khiển hoặc một cái gì đó, nhưng sau đó mỗi khi chúng tôi thêm hoặc xóa một cột, chúng tôi phải nhớ cập nhật tệp điều khiển. Tôi thích nói những điều một lần. Ngoài ra, khi màn hình chỉnh sửa được tạo hoàn toàn từ giản đồ, Thêm một bảng mới có nghĩa là viết không dòng mã nào để tạo màn hình chỉnh sửa cho nó, điều này thật tuyệt. (Chà, được rồi, trong thực tế, tôi thường phải thêm một mục vào menu để gọi chương trình chỉnh sửa chung chung và tôi thường từ bỏ việc "chọn bản ghi để cập nhật" chung chung vì có quá nhiều ngoại lệ để làm cho nó thực tế .)


1

Ngoài việc điều chỉnh hiệu suất rõ ràng, tôi vừa gặp phải một trường hợp góc trong đó việc sắp xếp lại các cột khiến một tập lệnh sql (trước đây có chức năng) bị lỗi.

Từ tài liệu "Các cột TIMESTAMP và DATETIME không có thuộc tính tự động trừ khi chúng được chỉ định rõ ràng, với ngoại lệ này: Theo mặc định, cột TIMESTAMP đầu tiên có cả DEFAULT CURRENT_TIMESTAMP và ON UPDATE CURRENT_TIMESTAMP nếu cả hai đều không được chỉ định rõ ràng" https: //dev.mysql .com / doc / refman / 5.6 / vi / timestamp-initialization.html

Vì vậy, một lệnh ALTER TABLE table_name MODIFY field_name timestamp(6) NOT NULL;sẽ hoạt động nếu trường đó là dấu thời gian đầu tiên (hoặc ngày giờ) trong bảng, nhưng không phải trường hợp khác.

Rõ ràng, bạn có thể sửa lệnh thay đổi đó để bao gồm một giá trị mặc định, nhưng thực tế là một truy vấn hoạt động đã ngừng hoạt động do sắp xếp lại cột khiến tôi đau đầu.


0

Lần duy nhất bạn cần phải lo lắng về thứ tự cột là nếu phần mềm của bạn đặc biệt dựa vào thứ tự đó. Thông thường, điều này là do thực tế là nhà phát triển đã lười biếng và thực hiện một select *và sau đó tham chiếu đến các cột theo chỉ mục thay vì theo tên trong kết quả của chúng.


0

Nói chung, những gì xảy ra trong SQL Server khi bạn thay đổi thứ tự cột thông qua Management Studio, đó là nó tạo một bảng tạm thời với cấu trúc mới, di chuyển dữ liệu đến cấu trúc đó từ bảng cũ, bỏ bảng cũ và đổi tên bảng mới. Như bạn có thể tưởng tượng, đây là một lựa chọn rất kém hiệu quả nếu bạn có một chiếc bàn lớn. Tôi không biết My SQL có làm như vậy không, nhưng đó là một lý do tại sao nhiều người trong chúng ta tránh sắp xếp lại các cột. Vì select * không bao giờ được sử dụng trong hệ thống sản xuất, nên việc thêm các cột ở cuối không phải là vấn đề đối với một hệ thống được thiết kế tốt. Thứ tự các cột trong bảng không được nhầm lẫn với nhau.


0

Năm 2002, Bill Thorsteinson đã đăng trên diễn đàn Hewlett Packard những gợi ý của ông về việc tối ưu hóa các truy vấn MySQL bằng cách sắp xếp lại các cột. Bài đăng của anh ấy kể từ đó đã được sao chép và dán ít nhất hàng trăm lần trên Internet, thường mà không cần trích dẫn. Để trích dẫn chính xác anh ta ...

Các quy tắc chung của ngón tay cái:

  • Các cột khóa chính đầu tiên.
  • Các cột khóa ngoại tiếp theo.
  • Các cột được tìm kiếm thường xuyên tiếp theo.
  • Các cột được cập nhật thường xuyên sau này.
  • Các cột có thể vô hiệu hóa cuối cùng.
  • Các cột nullable ít được sử dụng nhất sau các cột có thể rỗng được sử dụng thường xuyên hơn.
  • Các khối trong bảng riêng với vài cột khác.

Nguồn: Diễn đàn HP.

Nhưng bài đăng đó đã được thực hiện trở lại vào năm 2002! Lời khuyên này dành cho MySQL phiên bản 3.23, hơn sáu năm trước khi MySQL 5.1 được phát hành. Và không có tài liệu tham khảo hoặc trích dẫn. Vậy, Bill đã đúng? Và chính xác thì công cụ lưu trữ hoạt động như thế nào ở cấp độ này?

  1. Vâng, Bill đã đúng.
  2. Tất cả là vấn đề của các hàng chuỗi và các khối bộ nhớ.

Để trích dẫn Martin Zahn, một chuyên gia được Oracle chứng nhận , trong một bài báo về Bí mật của chuỗi liên kết và di chuyển hàng Oracle ...

Các hàng liên kết ảnh hưởng đến chúng ta khác nhau. Ở đây, nó phụ thuộc vào dữ liệu chúng ta cần. Nếu chúng ta có một hàng có hai cột được trải dài trên hai khối, truy vấn:

SELECT column1 FROM table

trong đó column1 nằm trong Khối 1, sẽ không gây ra bất kỳ «hàng tiếp tục tìm nạp bảng» nào. Nó sẽ không thực sự phải lấy column2, nó sẽ không theo hàng chuỗi trong suốt chặng đường. Mặt khác, nếu chúng ta yêu cầu:

SELECT column2 FROM table

và cột2 nằm trong Khối 2 do chuỗi liên kết hàng, khi đó trên thực tế, bạn sẽ thấy «hàng tiếp tục tìm nạp bảng»

Phần còn lại của bài báo là một bài đọc khá tốt! Nhưng tôi chỉ trích dẫn phần có liên quan trực tiếp đến câu hỏi của chúng tôi ở đây.

Hơn 18 năm sau, tôi phải nói: cảm ơn, Bill!

Ánh xạ một hàng MySQL thành một khối 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.