Những gì được lấy từ đĩa trong một truy vấn?


13

Câu hỏi khá đơn giản, có thể được trả lời ở đâu đó, nhưng dường như tôi không thể tạo thành câu hỏi tìm kiếm phù hợp cho Google ...

Số lượng cột trong một bảng cụ thể có ảnh hưởng đến hiệu suất của truy vấn không, khi truy vấn trên một tập hợp con của bảng đó?

Ví dụ: nếu bảng Foo có 20 cột, nhưng truy vấn của tôi chỉ chọn 5 trong số các cột đó, thì việc có 20 cột (so với giả sử là 10) có ảnh hưởng đến hiệu suất truy vấn không? Giả sử cho đơn giản rằng mọi thứ trong mệnh đề WHERE được bao gồm trong 5 cột đó.

Tôi lo ngại về việc sử dụng bộ đệm bộ đệm của Postgres ngoài bộ đệm đĩa của hệ điều hành. Tôi rất hiểu về thiết kế lưu trữ vật lý của Postgres. Các bảng được lưu trữ trên một số trang (mặc định có kích thước 8k cho mỗi trang), nhưng tôi không hiểu lắm về cách sắp xếp các bộ dữ liệu từ đó. PG có đủ thông minh để chỉ lấy từ đĩa dữ liệu bao gồm 5 cột đó không?


Bạn đang nói về việc tìm nạp 50 byte nhưng không phải là 150 byte còn lại. Đĩa của bạn có thể đọc với số lượng lớn hơn thế!
Andomar

Bạn lấy những con số đó từ đâu?
Jmoney38

Câu trả lời:


14

Bộ nhớ vật lý cho các hàng được mô tả trong các tài liệu trong Bố cục trang cơ sở dữ liệu . Tất cả các nội dung cột cho cùng một hàng đều được lưu trữ trong cùng một trang đĩa, ngoại trừ đáng chú ý là nội dung ed của TOAST (quá lớn để vừa trong một trang). Nội dung được trích xuất tuần tự trong mỗi hàng, như được giải thích:

Để đọc dữ liệu bạn cần kiểm tra lần lượt từng thuộc tính. Trước tiên hãy kiểm tra xem trường có phải là NULL theo bitmap không. Nếu có, đi tiếp theo. Sau đó hãy chắc chắn rằng bạn có sự liên kết đúng. Nếu trường là một trường có chiều rộng cố định, thì tất cả các byte được đặt đơn giản.

Trong trường hợp đơn giản nhất (không có cột TOAST), postgres sẽ tìm nạp toàn bộ hàng ngay cả khi cần vài cột. Vì vậy, trong trường hợp này, câu trả lời là có, việc có nhiều cột hơn có thể có tác động bất lợi rõ ràng đến bộ đệm bộ đệm, đặc biệt là nếu nội dung cột lớn trong khi vẫn ở dưới ngưỡng TOAST.

Bây giờ là trường hợp TOAST: khi một trường riêng lẻ vượt quá ~ 2kB, động cơ sẽ lưu trữ nội dung trường vào một bảng vật lý riêng. Nó cũng hoạt động khi toàn bộ hàng không vừa với một trang (8kB theo mặc định): một số trường được chuyển sang bộ lưu trữ TOAST. Bác sĩ nói:

Nếu đó là trường có chiều dài thay đổi (attlen = -1) thì phức tạp hơn một chút. Tất cả các kiểu dữ liệu có độ dài thay đổi đều chia sẻ cấu trúc tiêu đề cấu trúc chung, bao gồm tổng chiều dài của giá trị được lưu trữ và một số bit cờ. Tùy thuộc vào các cờ, dữ liệu có thể là nội tuyến hoặc trong bảng TOAST; nó cũng có thể bị nén

Nội dung của TOAST không được tìm nạp khi chúng không cần thiết rõ ràng, do đó, hiệu quả của chúng đối với tổng số trang cần tìm nạp là nhỏ (một vài byte trên mỗi cột). Điều này giải thích kết quả trong câu trả lời của @ dezso.

Đối với ghi, mỗi hàng với tất cả các cột của nó được viết lại hoàn toàn trên mỗi CẬP NHẬT, bất kể cột nào được thay đổi. Vì vậy, có nhiều cột rõ ràng là tốn kém hơn cho việc viết.


Đó là một câu trả lời kick-ass. Chính xác những gì tôi đang tìm kiếm. Cảm ơn bạn.
Jmoney38

1
Một tài nguyên tốt tôi tìm thấy liên quan đến cấu trúc hàng (pageinspect và một số cách sử dụng mẫu) ở đây .
Jmoney38

9

Câu trả lời của Daniel tập trung vào chi phí đọc từng hàng riêng lẻ. Trong ngữ cảnh này: Đặt NOT NULLcác cột có kích thước cố định đầu tiên trong bảng của bạn sẽ giúp một chút. Đặt các cột có liên quan trước (những cột bạn truy vấn) sẽ giúp một chút. Giảm thiểu phần đệm (do căn chỉnh dữ liệu) bằng cách chơi tetris căn chỉnh với các cột của bạn có thể giúp một chút. Nhưng hiệu ứng quan trọng nhất chưa được đề cập, đặc biệt là đối với các bảng lớn.

Các cột bổ sung rõ ràng làm cho một hàng chiếm nhiều không gian đĩa hơn, do đó, ít hàng hơn phù hợp trên một trang dữ liệu (theo mặc định 8 kB). Các hàng riêng lẻ được trải ra trên nhiều trang hơn. Công cụ cơ sở dữ liệu thường phải tìm nạp toàn bộ trang, không phải các hàng riêng lẻ . Nó ít quan trọng cho dù các hàng riêng lẻ có phần nhỏ hơn hoặc lớn hơn - miễn là cùng một số trang phải được đọc.

Nếu một truy vấn tìm nạp một phần nhỏ (tương đối) của một bảng lớn, trong đó các hàng được trải ra ít nhiều ngẫu nhiên trên toàn bộ bảng, được hỗ trợ bởi một chỉ mục, điều này sẽ dẫn đến số lần đọc trang tương tự, mà ít quan tâm đến cỡ hàng. Các cột không liên quan sẽ không làm bạn chậm lại nhiều trong trường hợp (hiếm) như vậy.

Thông thường, bạn sẽ tìm nạp các bản vá hoặc cụm hàng đã được nhập theo thứ tự hoặc gần và chia sẻ các trang dữ liệu. Những hàng đó được trải ra do sự lộn xộn, nhiều trang đĩa phải được đọc để đáp ứng truy vấn của bạn. Phải đọc nhiều trang thường là lý do quan trọng nhất khiến truy vấn bị chậm hơn. Và đó là yếu tố quan trọng nhất tại sao các cột không liên quan làm cho các truy vấn của bạn chậm hơn.

Với các cơ sở dữ liệu lớn, thường không đủ RAM để giữ tất cả trong bộ nhớ cache. Các hàng lớn hơn chiếm nhiều bộ đệm hơn, nhiều tranh chấp hơn, ít lần truy cập bộ đệm hơn, nhiều I / O đĩa hơn. Và đĩa đọc thường nhiều tốn kém hơn. Ít hơn với SSD, nhưng sự khác biệt đáng kể vẫn còn. Điều này thêm vào điểm trên về đọc trang.

có thể hoặc không quan trọng nếu các cột không liên quan là TOAST-ed. Các cột có liên quan cũng có thể là TOAST-ed, mang lại nhiều hiệu ứng tương tự.


1

Một bài kiểm tra nhỏ:

CREATE TABLE test2 (
    id serial PRIMARY KEY,
    num integer,
    short_text varchar(32),
    longer_text varchar(1000),
    long_long_text text
);

INSERT INTO test2 (num, short_text, longer_text, long_long_text)
SELECT i, lpad('', 32, 'abcdefeghji'), lpad('', 1000, 'abcdefeghji'), lpad('', (random() * 10000)::integer, 'abcdefeghji')
FROM generate_series(1, 10000) a(i);

ANALYZE test2;

SELECT * FROM test2;
[...]
Time: 1091.331 ms

SELECT num FROM test2;
[...]
Time: 21.310 ms

Giới hạn truy vấn trong 250 hàng đầu tiên ( WHERE num <= 250) cho kết quả lần lượt là 34,539 ms và 8,43 ms. Chọn tất cả nhưng long_long_texttừ kết quả thiết lập giới hạn này trong 18.432 ms. Điều này cho thấy trong điều khoản của bạn PG là đủ thông minh.


Vâng, tôi chắc chắn đánh giá cao đầu vào. Tuy nhiên, tôi không thể nói chắc chắn rằng kịch bản thử nghiệm này chứng minh những gì tôi đề xuất ban đầu. Có một vài vấn đề. Đối với một, khi bạn lần đầu tiên chạy "CHỌN * TỪ test2", điều đó sẽ lấp đầy bộ đệm bộ đệm chia sẻ của bạn. Truy vấn đó sẽ mất nhiều thời gian hơn để lấy từ đĩa. Do đó, về mặt lý thuyết, truy vấn thứ 2 sẽ nhanh hơn nhiều vì nó đã được tìm nạp từ bộ đệm SB. Nhưng tôi đồng ý rằng nó 'gợi ý' rằng PG chỉ tìm nạp các hàng cần thiết, dựa trên các thử nghiệm / so sánh sau này của bạn.
Jmoney38

Bạn đã đúng, bài kiểm tra này (đơn giản) có sai sót của nó. Nếu tôi có đủ thời gian, tôi cũng sẽ cố gắng bao gồm những điều này.
dezso
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.