Ồ, câu trả lời đúng "Không cho phép NULL khi bạn không phải làm thế vì chúng làm giảm hiệu suất" bằng cách nào đó là câu trả lời được xếp hạng cuối cùng. Tôi sẽ nâng cấp nó và xây dựng. Khi RDBMS cho phép NULL cho một cột không thưa thớt, cột đó được thêm vào một bitmap để theo dõi xem giá trị có phải là NULL cho mỗi hàng riêng lẻ hay không. Vì vậy, bằng cách thêm khả năng NULL vào một cột trong bảng trong đó tất cả các cột không cho phép NULL, bạn đang tăng không gian lưu trữ cần thiết để lưu bảng. Hơn nữa, bạn đang yêu cầu RDBMS đọc và ghi vào bitmap, làm giảm hiệu suất trên tất cả các hoạt động.
Hơn nữa, trong một số trường hợp, cho phép NULL sẽ phá vỡ 3NF. Mặc dù tôi không phải là người gắn bó với 3NF như nhiều đồng nghiệp của mình, hãy xem xét tình huống sau:
Trong bảng Person có một cột, được gọi là DateOfDeath, không có giá trị. Nếu một người đã chết, nó sẽ được điền vào DateOfDeath của họ, nếu không, nó sẽ bị bỏ lại NULL. Ngoài ra còn có một cột bit không nullable được gọi là IsAlive. Cột này được đặt thành 1 nếu người còn sống và 0 nếu người đó đã chết. Phần lớn các thủ tục được lưu trữ sử dụng cột IsAlive, họ chỉ quan tâm nếu một người còn sống chứ không phải DateOfDeath của họ.
Tuy nhiên, cột IsAlive phá vỡ chuẩn hóa cơ sở dữ liệu, vì nó hoàn toàn có thể lấy được từ DateOfDeath. Nhưng vì IsAlive được kết nối cứng vào phần lớn các SP, giải pháp đơn giản là làm cho DateOfDeath không thể rỗng và gán giá trị mặc định cho cột trong trường hợp người đó vẫn còn sống. Một số SP sử dụng DateOfDeath sau đó có thể được viết lại để kiểm tra cột IsAlive và chỉ tôn vinh DateOfDeath nếu người đó không còn sống. Một lần nữa, vì phần lớn các SP chỉ quan tâm đến IsAlive (một chút) chứ không phải DateOfDeath (một ngày) sử dụng mẫu này tăng tốc truy cập đáng kể.
Một tập lệnh T-SQL hữu ích để tìm các cột không thể có không có NULL trên tất cả các lược đồ là:
select 'IF NOT EXISTS (SELECT 1 FROM ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name) + ' WHERE ' + QUOTENAME(c.name) + ' IS NULL)
AND (SELECT COUNT(*) FROM ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name) + ') > 1 PRINT ''' + s.name + '.' + t.name + '.' + REPLACE(c.name, '''', '''''') + ''''
from sys.columns c
inner join sys.tables t ON c.object_id = t.object_id
inner join sys.schemas s ON s.schema_id = t.schema_id
where c.is_nullable = 1 AND c.is_computed = 0
order by s.name, t.name, c.name;
Nếu bạn chạy nó trên một bản sao của cơ sở dữ liệu sản xuất của bạn, bạn có thể tìm thấy các nhà phát triển cột được đánh dấu là cho phép các NULL không có NULL trong thực tế. Phần lớn trong số này có thể được đánh dấu là KHÔNG NULL, do đó tăng hiệu suất và giảm không gian lưu trữ.
Có thể không thể loại bỏ tất cả các NULL trong tất cả các bảng và vẫn có thiết kế rõ ràng, nhưng có một lợi thế đáng kể trong việc loại bỏ càng nhiều NULL càng tốt. Trình tối ưu hóa hoạt động nhanh hơn nhiều với thông tin này và nếu bạn có thể loại bỏ tất cả NULL trong một bảng, bạn có thể lấy lại một lượng không gian lưu trữ đáng kể.
Tôi biết rằng hiệu năng không phải là thứ mà các DBA nghĩ về tất cả, nhưng bạn chỉ có thể ném một lượng bộ nhớ và bộ xử lý hạn chế vào một giải pháp, một số điểm bạn sẽ phải bắt đầu nghĩ về thiết kế logic và vật lý .
Cũng lưu ý rằng điều này chỉ dành cho các RDBMS thực sự và tôi đang dựa vào phần kỹ thuật trong các câu trả lời của mình ngoài SQL Server. T-SQL được liệt kê để tìm các cột không có giá trị mà không có null cũng là từ SQL Server.