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:
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 :
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.
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 20
các cột.
Xem mục này trong blog của tôi để biết thêm chi tiết:
Trong Oracle
, NULL
cá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 Oracle
và SQL Server
, trong trường hợp của một hàng lớn, ROW CHAINING
có 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/O
thao tác bổ sung .
Xem trang này để minh họa ROW CHAINING
trong 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 @Andomar
câ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ì.
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ó.
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.
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.
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ó.
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.
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.
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ế .)
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.
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.
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?
Để 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!