2011-01-03 38 views
9

Thứ tự của các loại cột trong cơ sở dữ liệu của bạn có ảnh hưởng đến thời gian truy vấn không?Tốc độ truy vấn dựa trên thứ tự các cột

Ví dụ, một bảng có thứ tự hỗn hợp (INT, TEXT, VARCHAR, INT, TEXT) chậm hơn truy vấn so với bảng có loại liên tiếp (INT, INT, VARCHAR, TEXT, TEXT)?

Trả lời

8

Câu trả lời là có, nó quan trọng, và nó có thể quan trọng rất nhiều, nhưng thường là không nhiều.

Tất cả I/O được thực hiện ở cấp trang (thường là 2K hoặc 4K tùy thuộc vào hệ điều hành của bạn). Dữ liệu cột cho các hàng được lưu trữ bên cạnh nhau, trừ khi trang đầy, trong trường hợp dữ liệu được ghi trên trang khác (thường là trang tiếp theo).

Không gian dữ liệu trên đĩa lớn hơn cần thiết cho các cột giữa (dựa trên định nghĩa bảng) các cột bạn chọn, càng có nhiều khả năng dữ liệu cho các cột được chọn sẽ (đôi khi) trên các trang khác nhau. Đang ở trên một trang khác có thể dẫn đến hoạt động bổ sung I/O (nếu không có hàng nào khác được chọn trên trang khác). Trong trường hợp xấu nhất, mỗi cột bạn chọn có thể nằm trên một trang khác.

Dưới đây là một ví dụ:

create table bad_layout (
num1 int, 
large1 varchar(4000), 
num2 int, 
large2 varchar(4000), 
num3 int, 
large3 varchar(4000) 
); 

create table better_layout (
num1 int, 
num2 int, 
num3 int, 
large1 varchar(4000), 
large2 varchar(4000), 
large3 varchar(4000) 
); 

So sánh: chọn num1, num2, num3 từ bad_layout; chọn num1, num2, num3 từ better_layout;

Bởi vì đối với bad_layout, mỗi cột num về cơ bản sẽ nằm trên một trang khác, mỗi hàng sẽ yêu cầu 3 hoạt động i/O. Ngược lại, đối với các cột num số_lượng tốt hơn thường xuất hiện trên cùng một trang.

Truy vấn bad_layout có thể mất khoảng 3 lần để thực thi.

Bố cục bảng tốt có thể tạo sự khác biệt lớn về hiệu suất truy vấn. Bạn nên cố gắng giữ cho các cột thường được chọn gần nhau nhất có thể với nhau trong bố cục bảng.

+0

Điều đó có ý nghĩa; có ai quan tâm để kiểm tra nó không? Tôi không có một cài đặt PostgreSQL tiện dụng. –

+0

Sẽ không [TOAST] (http://www.postgresql.org/docs/9.4/static/storage-toast.html) phần lớn ngăn các giá trị cột lớn gây ra loại sự cố này? Ngoài ra, tài liệu đó (nếu tôi đọc nó một cách chính xác) tuyên bố rõ ràng rằng một tuple hàng không được phép span nhiều trang. – jpmc26

5

Thứ tự dường như không quan trọng lắm. Thời gian chạy bị chi phối bởi những thứ như thời gian truy cập đĩa, và số lượng và thứ tự truy cập đĩa không có khả năng thay đổi do kết quả sắp xếp lại dữ liệu trong một hàng.

Một ngoại lệ là nếu bạn có một mục rất lớn trong hàng của bạn (lớn hơn nhiều so với khối đĩa, thường là 4K?). Nếu bạn có một cột rất lớn trong một bảng, bạn có thể muốn đặt nó làm cột cuối cùng để nếu bạn không truy cập vào nó, nó có thể không cần phải được phân trang đầy đủ. Nhưng thậm chí sau đó, bạn phải làm việc khá khó khăn để tạo ra một tập dữ liệu và mô hình truy cập nơi sự khác biệt sẽ được chú ý.

+1

Thực ra tôi nghĩ ngay cả cột "lớn" ở giữa mà bạn không chọn sẽ không tạo ra sự khác biệt. Nếu nó lớn, nó sẽ được TOASTed anyway. Vì vậy, dữ liệu cột thực sẽ không nằm trong các khối bảng bình thường và bảng TOAST sẽ không được chạm nếu cột không được chọn –

3

Trong PostgreSQL, bạn sẽ nhận được một lợi thế nếu bạn đặt cột cố định chiều rộng đầu tiên bởi vì đường dẫn truy cập được tối ưu hóa đặc biệt. Vì vậy, (INT, INT, VARCHAR, TEXT, TEXT) sẽ nhanh nhất (thứ tự tương đối của VARCHAR và TEXT không quan trọng).

Ngoài ra, bạn có thể tiết kiệm dung lượng, có thể dịch thành nhiều thông lượng và hiệu suất hơn, nếu bạn quản lý các yêu cầu căn chỉnh của các loại chính xác. Ví dụ, (INT, BOOL, INT, BOOL) sẽ yêu cầu 13 byte không gian vì cột thứ ba phải được căn chỉnh tại ranh giới 4 byte, và do đó sẽ có 3 byte không gian bị lãng phí giữa cột thứ hai và cột thứ ba . Tốt hơn ở đây sẽ là (INT, INT, BOOL, BOOL). (Bất cứ điều gì đến sau hàng này có thể cũng sẽ yêu cầu sự liên kết của ít nhất 4 byte, vì vậy bạn sẽ lãng phí 2 byte ở cuối.)

+1

Đó là liên kết, không biết điều đó. Bạn có bất kỳ tham chiếu đến chủ đề này? – DrColossos

+1

Điều này chủ yếu là từ kiến ​​thức mã nguồn của tôi. Tìm kiếm 'fastgetattr' nếu bạn muốn đi sâu vào nó. –

+0

Tôi rất muốn xem một ví dụ làm việc chứng minh điều này. Đây có phải là nhiều hơn dựa trên mã có một sự khác biệt, nhưng trong thế giới thực, bạn sẽ không bao giờ thực sự nhận thấy một điều thực sự loại khác biệt? Có lẽ với một số thời gian rảnh rỗi tôi sẽ chơi xung quanh với một ví dụ và đăng bài nếu tôi có thể. – Kuberchaun

0

Tôi đề nghị rằng hoàn toàn không có sự khác biệt [đáng kể] bất kể bạn đặt hàng các cột như thế nào.

PostgreSQL: http://social.msdn.microsoft.com/Forums/en-US/sqldatabaseengine/thread/a7ce8a90-22fc-456d-9f56-4956c42a78b0

SQL Server: http://social.msdn.microsoft.com/Forums/en/sqldatabaseengine/thread/36713a82-315d-45ef-b74e-5f342e0f22fa

tôi nghi ngờ tương tự cho MySQL.

Tất cả dữ liệu được đọc trong các trang, vì vậy nếu dữ liệu của bạn phù hợp với một trang, không quan trọng bạn đặt hàng các cột như thế nào. Nếu kích thước khối đĩa là 2K, 4K, nó sẽ lấy nhiều thứ để thỏa mãn "8K yêu cầu trang". Nếu kích thước khối đĩa là 64K (đối với các hệ thống DB lớn), bạn đã có thể đệm các dữ liệu khác.

Không chỉ vậy, nếu một bản ghi được yêu cầu, thông thường sẽ truy xuất tất cả các trang cho bản ghi, bao gồm phần tràn vào trang 2 và 3 nếu dữ liệu kéo dài nhiều trang. Các cột sau đó được tính từ dữ liệu được truy xuất. SQL Server có giới hạn về dữ liệu trong trang, khoảng 8060 byte. Mọi thứ lớn hơn được lưu trữ trên trang dữ liệu chính, tương tự như TOAST cho PostgreSQL và không được truy xuất nếu cột không được sử dụng. Nó vẫn còn không quan trọng vị trí của cột theo thứ tự.

Trong SQL Server ví dụ, nhiều trường bit được lưu trữ cùng nhau trong một mặt nạ khuôn mẫu bit - điều này là không phân biệt cho dù bạn đặt các cột bên cạnh nhau. Tôi nghi ngờ MySQL và PostgreSQL sẽ làm nhiều việc như vậy để tối ưu hóa không gian.

Lưu ý: [quan trọng] - lý do duy nhất cho tiêu chuẩn này là, có thể, khi trích xuất một cột cụ thể từ trang dữ liệu, có nó ngay từ đầu giúp vì cuộc gọi hội nghị cấp thấp không phải tìm kiếm xa trong khối bộ nhớ.

Các vấn đề liên quan