Hậu quả của việc không chỉ định KHÔNG NULL trong PostgreSQL đối với các trường không thể là null là gì?


10

Tôi có một ứng dụng (dữ liệu được lưu trữ trong PostgreSQL), trong đó phần lớn các trường trong các bảng luôn không phải là null, nhưng lược đồ cho các bảng này không thực thi điều này. Ví dụ nhìn vào bảng giả mạo này:

CREATE TABLE "tbl" (
    "id" serial,
    "name" varchar(40),
    "num" int,
    "time" timestamp
    PRIMARY KEY ("id"),
    UNIQUE ("id")
);

Ngoài ra name, num, timekhông được quy định rõ ràng như NOT NULLtrên thực tế họ đang có, bởi vì thực thi xảy ra ở phía ứng dụng.


Cảm giác của tôi là nó nên được thay đổi, nhưng điều ngược lại là mức độ ứng dụng đảm bảo rằng các giá trị null không thể xuất hiện ở đây và không ai khác tự sửa đổi bảng.

Câu hỏi của tôi là : lợi ích (hiệu suất, lưu trữ, tính nhất quán, cái gì khác) và nhược điểm (giả sử rằng tôi đã xác minh rằng hiện tại không có null nào và từ logic nghiệp vụ sẽ không có null) bằng cách đặt ràng NOT NULLbuộc rõ ràng?

Chúng tôi có quy trình xem xét mã tốt và tài liệu hợp lý tốt, vì vậy khả năng một số người mới sẽ cam kết điều gì đó phá vỡ ràng buộc này là không thực sự đủ để biện minh cho sự thay đổi.

Đây không phải là quyết định của tôi, vì vậy đây chính xác là lý do tại sao tôi đang tìm kiếm những lời biện minh khác. Theo tôi, nếu một cái gì đó không thể là null và cơ sở dữ liệu cho phép bạn chỉ định rằng một cái gì đó không phải là null - thì hãy làm điều đó. Đặc biệt nếu thay đổi là siêu đơn giản.


1
Xem câu trả lời này cho các cân nhắc về Nulls và dung lượng ổ đĩa: stackoverflow.com/questions/5008753/, Nói tóm lại, nếu bảng của bạn có nhiều hơn 8 cột và ít nhất 1 cột rỗng, thì bảng sẽ cần nhiều byte hơn mỗi hàng so với nếu tất cả các cột đều định nghĩa không null.
ypercubeᵀᴹ

1
@ ypercubeᵀᴹ: Nói chính xác, bitmap null chỉ được thêm vào mỗi hàng nếu có giá trị null thực tế trong hàng: stackoverflow.com/a/7654497/939860 . Do đó, các NOT NULLràng buộc không có bất kỳ ảnh hưởng trực tiếp đến kích thước lưu trữ. Tất nhiên, với tất cả các cột được xác định NOT NULL, không thể có một bitmap null để bắt đầu. Mặt khác: kích thước lưu trữ thường nhỏ hơn nhiều nếu bạn sử dụng NULL thay vì giá trị "trống" hoặc giá trị giả cho các cột không có giá trị thực tế, vì bitmap null tương đối nhỏ hơn nhiều (trừ trường hợp cạnh hiếm).
Erwin Brandstetter

@ErwinBrandstetter xấu của tôi sau đó, đã không hiểu phần đó. Vì vậy, đối với các cột không có giá trị null, không có sự khác biệt thực sự về lưu trữ, cho dù bạn xác định chúng là NULL hay KHÔNG NULL, đúng không? Điều đó có giống với không gian lưu trữ chỉ mục không?
ypercubeᵀᴹ

5
"Cấp độ ứng dụng đảm bảo rằng các giá trị null không thể xuất hiện ở đây" Không, không. Nó có thể đảm bảo rằng một ứng dụng không chèn null. Nhưng tôi có psql (ví dụ) và tôi có thể chèn null cả cố ý và vô tình mà không có ứng dụng của bạn biết về nó.
Mike Sherrill 'Nhớ lại mèo'

4
Ứng dụng duy nhất có thể đảm bảo không ai sửa đổi bảng theo cách thủ công là chính dbms.
Mike Sherrill 'Nhớ lại mèo'

Câu trả lời:


9

Điều gì xảy ra khi một lập trình viên mới đến và phải viết một ứng dụng chống lại db đó? Họ không biết rằng lĩnh vực x được NOT NULL.

Một chương trình khác có thể giả định rằng tất cả các trường x là NOT NULLđể thực hiện số lượng nói, nhưng một số hiện tại là NULLdo chương trình mới, dẫn đến lỗi không nhất quán và khó theo dõi.

IMHO luôn luôn tốt nhất để thực thi các quy tắc toàn vẹn dữ liệu càng gần dữ liệu càng tốt, tức là trong cơ sở dữ liệu. Bằng cách đó, các ứng dụng và / hoặc lập trình viên mới không thể làm xáo trộn dữ liệu của bạn.

Lập trình viên, ứng dụng, ngôn ngữ và khung đến và đi. Dữ liệu và cơ sở dữ liệu có xu hướng tồn tại. Cơ sở dữ liệu là tuyến phòng thủ cuối cùng của bạn chống lại dữ liệu không nhất quán, có khả năng bị lỗi.

Hãy tối đa sử dụng các cơ chế thực thi toàn vẹn hạn chế của cơ sở dữ liệu của bạn, thậm chí phải trả giá bằng hiệu suất. Một hệ thống chậm tạo ra kết quả chính xác là vô cùng vượt trội so với hệ thống nhanh khiến mọi thứ trở nên sai lầm!


1
IMHO it is always best to enforce data integrity rules as near to the data as possibleđiều này thực sự giống như cảm giác ruột thịt mà tôi đã viết. Và đây chính xác là lý do tại sao tôi đang tìm kiếm những lời biện minh thực sự. Chúng tôi có đánh giá mã tại chỗ và tài liệu tốt, vì vậy những lo ngại về một nhà phát triển mới không biết điều gì đó là không đủ để biện minh cho sự thay đổi.
Salvador Dali

4
Đánh giá mã và tài liệu tốt không đảm bảo cho bạn chống lại lỗi (lập trình hoặc khác).
ypercubeᵀᴹ

2
Và có bao nhiêu người REAL PROGRAMMERSđọc tất cả (hoặc thậm chí bất kỳ) tài liệu nào trước khi bị mắc kẹt trong một dự đoán khi chúng đang trong thời hạn chặt chẽ?
Vérace

3
Tôi đã từng làm một bài đánh giá trong một ngân hàng có cùng thái độ với kho dữ liệu của họ. Trong trường hợp của họ - không có tính toàn vẹn tham chiếu. Chà, xảy ra 40% dữ liệu cũ là rác vì ai đó đã không đọc tài liệu và xóa dữ liệu trong các bảng tra cứu. Bạn không tin tưởng các đánh giá và tài liệu mã với tính toàn vẹn dữ liệu - bạn làm cho nó rõ ràng trong cơ sở dữ liệu.
TomTom

5

Như đã được trích dẫn bởi những người khác trong các nhận xét, việc thêm NOT NULLvào đặc tả bảng của bạn có thể cải thiện một cách đáng kể hiệu suất của các truy vấn của bạn (ngoài các lý do phương pháp rất tốt được nêu trong câu trả lời khác).

Lý do là trình tối ưu hóa truy vấn, biết rằng một cột không thể có NULLgiá trị, có thể loại trừ các kiểm tra đặc biệt cho các giá trị đó, như trong trường hợp NOT INso với NOT EXISTS. Ví dụ , bạn có thể thấy blog này , nơi nó được hiển thị rằng không khai báo một trường NOT NULL(khi bảng luôn chứa các giá trị không null) với một truy vấn nhất định sẽ tăng thời gian thực hiện 500%. Kết quả được hiển thị cho SQL Server, nhưng một hành vi tương tự có thể xuất hiện trong các DBMS quan hệ khác, như của bạn (không đề cập đến thực tế là cơ sở dữ liệu của bạn có thể được chuyển sang các hệ thống khác). Một quy tắc chung mà bạn có thể giả định là khi có nhiều thông tin hơn cho trình tối ưu hóa truy vấn, thì các kế hoạch truy cập hiệu quả hơn có thể được tạo ra.


Cảm ơn bạn. Đây là loại câu trả lời tôi đang tìm kiếm.
Salvador Dali

5
Các cột không bao giờ chứa NULL, nên được xác định NOT NULLvì nhiều lý do, không có đối số về điều đó. Nhưng liên kết đến blog về SQL Server không thể áp dụng cho Postgres và không chứng minh bất kỳ hàm ý hiệu suất nào mà bạn đề cập. Không nói là không có, nhưng tôi rất thích xem bằng chứng thực tế .
Erwin Brandstetter

@ErwinBrandstetter, tôi đã có nhiều đánh giá cao về trình tối ưu hóa PostgreQuery :( Sau nhiều thử nghiệm, tôi không tìm thấy sự khác biệt đáng kể nào trong truy vấn NOT IN được trình bày trong blog trong PostgreQuery có và không có ràng buộc KHÔNG NULL. Vì vậy, tôi đã thay đổi câu trả lời. và đang hỏi bạn nếu bạn nghĩ rằng tôi nên xóa nó hoàn toàn.
Renzo

Không, tôi không nghĩ rằng nó nên bị xóa. Nó có 5 phiếu bầu và không có downvote, cho một.
ypercubeᵀᴹ

Các ngữ nghĩa của not incác cột nullable là khác nhau mặc dù vậy phải có một số khác biệt trong kế hoạch giữa hai cột?
Martin Smith

2

Hàm ý không gian

Ý nghĩa không gian được nói đến trong bài viết này của @Erwin Brandstetter

Nói tóm lại, bạn sẽ lưu một totalColumns - 8bit được làm tròn đến byte (hoặc MAXALIGN) gần nhất , nếu cơ sở dữ liệu của bạn có

  1. Hơn 8 cột
  2. TẤT CẢ các cột trên bàn làNOT NULL

Ý nghĩa hiệu suất

Tuy nhiên, trong bài đăng này trên SE của @Erwin Brandstetter , ông nói

  1. "Cài đặt KHÔNG NULL không ảnh hưởng đến hiệu suất. Một vài chu kỳ cho việc kiểm tra - không liên quan."
  2. "... bằng cách thực sự sử dụng NULL thay vì giá trị giả. Tùy thuộc vào loại dữ liệu, bạn có thể tiết kiệm rất nhiều dung lượng đĩa và RAM, do đó tăng tốc .. mọi thứ."

@Renzo có một câu trả lời nói về ý nghĩa hiệu năng - Tôi sẽ cho rằng không có câu trả lời nào phù hợp với PostgreQuery . Tôi không thể tìm thấy bất cứ điều gì chứng minh bất kỳ điều gì có liên quan đến PostgreSQL. Bất kỳ chu kỳ nào được lưu không thể được định lượng trong ngay cả truy vấn thô sơ nhất.

CREATE TABLE foo (
  a int,
  b int NOT NULL,
  x float,
  y float NOT NULL
);

INSERT INTO foo ( a, b, x, y )
SELECT x, x, x, x
FROM generate_series(1,1E7) AS X(x);

EXPLAIN ANALYZE SELECT 1/a FROM foo;
EXPLAIN ANALYZE SELECT 1/b FROM foo;
EXPLAIN ANALYZE SELECT 1/x FROM foo;
EXPLAIN ANALYZE SELECT 1/y FROM foo;

Ngoài ra, tôi đã chạy một số thử nghiệm để xem liệu chỉ số NULL có nhanh hơn không và tôi không thể chứng minh điều đó. Bạn có thể tìm thấy chủ đề cực kỳ hữu ích này của Scott Marlowe trong danh sách gửi thư nói về trình hoạch định truy vấn trong 9.1 có thể sử dụng chỉ mục một phần trên các mệnh đề WHERE khác nhau. Tôi đã thử nghiệm điều này bằng cách chạy như sau

CREATE TABLE foo ( a int );
CREATE TABLE bar ( a int NOT NULL );
INSERT INTO foo
  SELECT null FROM generate_series(1,1e5) AS x
  UNION ALL
  SELECT 10
  UNION ALL
  SELECT null FROM generate_series(1,1e5) AS x
;
INSERT INTO bar
  SELECT 0 FROM generate_series(1,1e5) AS x
  UNION ALL
  SELECT 10
  UNION ALL
  SELECT 0 FROM generate_series(1,1e5) AS x
;

Bây giờ tôi đã tạo các chỉ mục,

CREATE INDEX foobar ON foo(a) WHERE a IS NOT NULL;
CREATE INDEX barbar ON bar(a) WHERE a <> 0;

Trong cả hai trường hợp này, trình hoạch định có thể sử dụng chỉ mục khi chọn = 10và sử dụng quét seq khi tìm kiếm NULL hoặc 0 tương ứng. Cả hai chỉ số một phần có cùng kích thước. Và, các chỉ mục đầy đủ (không hiển thị) có cùng kích thước. Theo cùng một phương pháp, tôi đã tải lên bảng với một chuỗi 1..1e5và một giá trị null / 0 và một chuỗi khác 1..1e5. Cả hai phương pháp đều có thể tìm thấy null / 0 với một chỉ mục bao trùm toàn bộ bảng.

TLDR; Tóm lược

Tôi không thể chứng minh bất cứ điều gì bằng cách này hay cách khác trên hầu hết các mối quan tâm về hiệu suất mà tôi nghĩ là đáng để kiểm tra bao gồm cả những bất cập của người lập kế hoạch. Lợi ích của việc sử dụng null để lưu ram là có thật. Không gian đĩa được lưu bằng cách không sử dụng null là không đáng kể và đó là sự quá lời trên các bảng có một NULLABLEcột hoặc ít hơn 8 cột. Trong những trường hợp không có không gian đĩa được lư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.