MySQL LÀ NULL / LÀ NULL Misbehaving?


18

Xin vui lòng xem bảng này:

mysql> desc s_p;

+-------------------------+------------------+------+-----+---------+----------------+    
| Field                   | Type             | Null | Key | Default | Extra          |
+-------------------------+------------------+------+-----+---------+----------------+
| id                      | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| s_pid                   | int(10) unsigned | YES  | MUL | NULL    |                |
| sm_id                   | int(10) unsigned | YES  | MUL | NULL    |                |
| m_id                    | int(10) unsigned | YES  |     | NULL    |                |
| created                 | datetime         | YES  |     | NULL    |                |
| s_date                  | datetime         | YES  |     | NULL    |                |
| estimated_date          | datetime         | YES  | MUL | NULL    |                |
+-------------------------+------------------+------+-----+---------+----------------+

Bây giờ hãy xem các truy vấn sau:

mysql> select count(*) from s_p where estimated_date is null;
+----------+
| count(*) |
+----------+
|   190580 |
+----------+
1 row in set (0.05 sec)

mysql> select count(*) from s_p where estimated_date is not null;
+----------+
| count(*) |
+----------+
|    35640 |
+----------+
1 row in set (0.07 sec)

mysql> select count(*) from s_p;
+----------+
| count(*) |
+----------+
|  1524785 |
+----------+

Số lượng ở trên không phù hợp. Trong khi theo sự hiểu biết của tôi:

Đếm với IS NULLvà Đếm với IS NOT NULLnên bằng với đếm khi được truy vấn mà không có mệnh đề where.

Bất cứ ý tưởng về những gì đang xảy ra ở đây?

================================================== = =

Cập nhật vào ngày 17 tháng 2 năm 2012

Kể từ đó, tôi thấy rằng rất nhiều người đang hỏi về loại giá trị ước tính hiện có. Đây là câu trả lời:

mysql> select distinct date(estimated_date) from s_p;

+----------------------+
| date(estimated_date) |
+----------------------+
| NULL                 |
| 2012-02-17           |
| 2012-02-20           |
| 2012-02-21           |
| 2012-02-22           |
| 2012-02-23           |
| 2012-02-24           |
| 2012-02-27           |
| 2012-02-28           |
+----------------------+
9 rows in set (0.42 sec)

Như bạn có thể thấy ước tính ở trên có NULL hoặc giá trị datetime hợp lệ. Không có số không hoặc chuỗi trống "".

Điều này (vấn đề ban đầu) có thể xảy ra nếu chỉ mục trên valu_date có một số vấn đề / s không?

================================================== = =

Cập nhật vào ngày 18 tháng 2 năm 2012

Dưới đây là chương trình tạo bảng đầu ra:

 | s_p | CREATE TABLE `s_p` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `s_id` int(10) unsigned DEFAULT NULL,
  `sm_id` int(10) unsigned DEFAULT NULL,
  `m_id` int(10) unsigned DEFAULT NULL,
  `created` datetime DEFAULT NULL,
  `estimated_date` datetime DEFAULT NULL,
   PRIMARY KEY (`id`),
   KEY `sm_id` (`sm_id`),
   KEY `estimated_date_index` (`estimated_date`) USING BTREE,
  ) ENGINE=InnoDB AUTO_INCREMENT=1602491 DEFAULT CHARSET=utf8 |

Một lần nữa, tôi chỉ có thể nghi ngờ chỉ số trên ước tính tại đây.

Ngoài ra, phiên bản máy chủ mysql là 5.5.12.


3
Trừ khi bảng được cung cấp các hàng mới giữa và trong khi chạy 3 truy vấn, điều này không thể xảy ra!
ypercubeᵀᴹ

6
Bạn có chắc chắn rằng bạn đang làm select count(*)và không select count(estimated_date)? Hai cái này sẽ trả về các kết quả khác nhau vì NULL bị bỏ qua nếu đó là điều duy nhất bạn đang đếm.

6
Tôi không chắc liệu các tính năng sau có hoạt động trong MySQL hay không, nhưng bạn có thể thử chạy không: SELECT COUNT(*),SUM(CASE WHEN estimated_date IS NULL THEN 1 ELSE 0 END),SUM(CASE WHEN estimated_date IS NOT NULL THEN 1 ELSE 0 END) from s_p- sẽ nhận được tất cả số đếm trong một lần.
Damien_The_Unbeliever

1
Đây có phải là những truy vấn chính xác mà bạn đang chạy không?
gbn

4
Ngoài ra, nếu đây là MyISAM, bạn có thể chạy CHECK TABLEtrên nó không? Xét một cách hoang dại đếm đầy đủ hàng lớn hơn, tôi đoán một DELETEđi đâu đó điên.
Naltharial

Câu trả lời:


6

Bạn có một số ngày không? Các giá trị thời gian 0000-00-00 00:00:00được MySQL xem xét để đồng thời thỏa mãn is nullis not null:

steve@steve@localhost > create temporary table _tmp (a datetime not null);
Query OK, 0 rows affected (0.02 sec)

steve@steve@localhost > insert into _tmp values ('');
Query OK, 1 row affected, 1 warning (0.00 sec)

Warning (Code 1264): Out of range value for column 'a' at row 1
steve@steve@localhost > select a from _tmp where a is null;
+---------------------+
| a                   |
+---------------------+
| 0000-00-00 00:00:00 |
+---------------------+
1 row in set (0.00 sec)

steve@steve@localhost > select a from _tmp where a is not null;
+---------------------+
| a                   |
+---------------------+
| 0000-00-00 00:00:00 |
+---------------------+
1 row in set (0.00 sec)

Xem: http://bugs.mysql.com/orms.php?id=940

Điều này được phân loại là "không phải là một lỗi". Họ đề xuất một cách giải quyết: sử dụng chế độ nghiêm ngặt, sẽ chuyển cảnh báo chèn thành lỗi.

Đã nói tất cả, điều này một mình không thể giải thích sự khác biệt lớn trong kết quả bạn nhận được (tổng của is nullis not nulltổng số vượt quá số lượng không giới hạn) ...


Lỗi xuất hiện khi DATEhoặc DATETIMEđược định nghĩa là NOT NULL. Trong câu hỏi ở đây, cột được định nghĩa là nullable. Tuy nhiên, lỗi này là một lý do khác để chỉ chạy MySQL ở chế độ nghiêm ngặt.
ypercubeᵀᴹ

Tôi đã cập nhật bài viết gốc để hiển thị các giá trị hiện tại trong cột ước tính. Nó không có 0000-00-00 hoặc chuỗi trống "".
dùng1213259

1
@yper hoặc một lý do để chọn một DBMS khác ...
ErikE

1
@ErikE: Điều đó, đôi khi, không phải là một sự lựa chọn. Và bạn sẽ luôn tìm thấy lý do để chọn DBMS anotehr, bất cứ thứ gì bạn đang làm việc cùng.
ypercubeᵀᴹ

FYI ToadQuery hiển thị 0000-00-00 00:00:00 dưới dạng {null}, tiếp tục làm vấy bẩn vùng biển! Thật là một cơn ác mộng. FTR chúng tôi không có một chỉ mục trên cột vấn đề của chúng tôi. Đây là ngày 5.6.15-log.
sming

3

@ypercube:

Gần đây tôi đã được hỏi liệu tôi có nghĩ rằng lỗi hồi quy "CHỌN COUNT (DISTINCT) gặp sự cố InnoDB khi toán hạng WHERE nằm trong Khóa chính hoặc Chỉ mục duy nhất" có thể là gốc rễ của điều này.

Đây là câu trả lời của tôi (ban đầu ở đây):

http://www.chrryptender.com/?p=315&cpage=1#comment-1460

Tôi không nghĩ rằng đây là cùng một lỗi. Lỗi này liên quan nhiều hơn đến sự cố và yêu cầu cụ thể CHỌN QUỐC GIA (DISTINCT), cộng với toán hạng WHERE nằm trong Chỉ mục chính hoặc Chỉ mục duy nhất.

Lỗi / sự cố của bạn không có DISTINCT, nó không bị sập và chỉ mục trên cột datetime không phải là khóa chính cũng không phải là duy nhất. Tuy nhiên, nó hơi lạ một chút, vì vậy tôi đã thực hiện một số tìm kiếm và chạy qua lỗi này, có vẻ như có liên quan / liên quan nhiều hơn:

http://bugs.mysql.com/orms.php?id=60105

Trên thực tế, nó được chỉ định là không phải là lỗi bug, nhưng nó cho thấy / mô tả cách bạn có thể gặp phải hành vi lạ khi bạn có ngày / giờ dữ liệu với '0000-00-00 và sử dụng IS NULL và IS NULL.

Tôi tự hỏi nếu bạn có bất kỳ hàng nào trong số 0000-00-00 này có thể ảnh hưởng đến số lượng?

Lưu ý rằng Dev, những người bình luận trong báo cáo lỗi cũng đề cập đến trang này:

Nếu không phải vậy, tôi chắc chắn khuyên bạn nên nâng cấp và thử bản này trên phiên bản 5.5 mới nhất, tức là 5.5,21 (kể từ ngày 22/2/2012), vì đã được 9 tháng (và 9 bản phát hành) kể từ 5.5.12 đã được phát hành.

Lưu ý rằng bạn sẽ có thể kết xuất bảng (và dữ liệu) và nhập nó vào một phiên bản thử nghiệm khác, chỉ để kiểm tra nó. Bằng cách đó, bạn không ảnh hưởng đến máy sản xuất và bạn có thể có một phiên bản thử nghiệm được thiết lập trong vài phút.

Sau đó, nếu điều đó không tạo ra sự khác biệt, bạn sẽ có thể thử nghiệm một số mặt hàng khác, chẳng hạn như có thể chuyển đổi bảng thành MyISAM để xem vấn đề có phải là vấn đề toàn cầu hay chỉ cụ thể đối với InnoDB.

Hoặc, tôi nhận thấy chỉ số trên 'valu_date' là:

KEY estimated_date_index( estimated_date) SỬ DỤNG BTREE

Lưu ý những người sử dụng BTREE rèn. Có lẽ hãy thử nó mà không cần sử dụng BTREE và xem nếu bạn vẫn thấy hành vi tương tự. (Hoặc loại bỏ chỉ mục hoàn toàn chỉ để kiểm tra .. tất cả sẽ giúp thu hẹp vấn đề).

Hi vọng điêu nay co ich.


1

Hãy thử truy vấn

select * from s_p where estimated_date is null and estimated_date is not null limit 5;

Tôi không nghĩ bạn hiểu câu hỏi là gì.

2
Truy vấn trên sẽ hiển thị các hàng ứng xử sai mà bạn có thể tìm thấy giải pháp.

1
Nếu truy vấn đó trả về bất kỳ hàng nào, tôi thực sự lo lắng về tính toàn vẹn của dữ liệu của bạn.
Naltharial

@Naltharial Đó không phải là dữ liệu của tôi, Câu hỏi trên cho kết quả kỳ lạ.

mysql chọn * từ s_p trong đó Ước tính là null và ước tính không phải là giới hạn null 5; Tập rỗng (0,00 giây)
user1213259 17/212

1

Tôi thấy một cái gì đó thú vị trong cách bố trí bảng kêu lên 'Tôi không cảm thấy muốn đếm'. Những gì tôi sắp nói chỉ là một linh cảm.

Bạn đã chạy truy vấn này trước

select distinct date(estimated_date) from s_p;

Chạy nó dưới dạng COUNT / GROUP BY

select count(1) rowcount,date(estimated_date) from s_p group by date(estimated_date);

Bạn sẽ nhận được số lượng dứt khoát bạn đang tìm kiếm.

Tuy nhiên, tại sao số đếm cho NULL và KHÔNG NULL sẽ tính toán chính xác? Một lần nữa, đây chỉ là một phỏng đoán có giáo dục.

Bạn có cột estimated_dateđược lập chỉ mục. Đây là những gì tôi muốn bạn thử:

SHOW INDEX FROM s_p;
SHOW INDEX FROM s_p;
SHOW INDEX FROM s_p;
SHOW INDEX FROM s_p;

Đó không phải là một lỗi đánh máy. Tôi muốn bạn chạy SHOW INDEX FROM s_p;bốn (4) lần. Nhìn vào Cardinalitycột. Kể từ khi bàns_p trong InnoDB, tôi hy vọng cột Cardinality sẽ khác nhau mỗi lần. Tại sao?

InnoDB có được giá trị Cardinality bằng cách ước tính nó (KHÔNG CÓ HIỆU LỰC) bằng cách đếm qua các mục trang BTREE. Kiểm tra biến hệ thống của bạn innodb_stats_on_metadata . Nó nên được kích hoạt. Nếu nó đã được bật, hãy tắt nó và chạy lại các truy vấn ban đầu của bạn để xem có cải thiện mọi thứ không. HÃY CHỈ NÀY NHƯ MỘT CUỘC SỐNG CUỐI CÙNG !!!

Vì vậy, thay vì các truy vấn sau:

select count(*) from s_p where estimated_date is null;
select count(*) from s_p where estimated_date is not null;

Thử

select count(estimated_date) from s_p;

Điều này sẽ cung cấp cho bạn số lượng hàng với ước tính không null.

Một cách tiếp cận khác mà bạn có thể muốn thử nghiệm với truy vấn vũ phu này bằng cách sử dụng chức năng ISNULL :

select count(*) rowcount,isnull(estimated_date) IsItNull
from s_p group by isnull(estimated_date);

Tôi hy vọng những gợi ý này giúp !!!


-4

Điều này được mong đợi. Đối với một cột không có giá trị, 0 == NULL = "", v.v. Vì vậy, kiểm tra đầu tiên thực sự trả về các hàng trong đó không có ngày nào được đặt hoặc cảm nhận của nó tương tự như "0 / NULL"


2
0không bao giờ bằng NULL. Chuỗi rỗng ( '') không giống như NULLmột trong hai, trừ khi bạn đang làm việc với Oracle.
ypercubeᵀᴹ
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.