it-swarm.asia

MySQL IS NULL / IS BUKAN NULL?)

Silakan lihat tabel ini:

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    |                |
+-------------------------+------------------+------+-----+---------+----------------+

Sekarang Lihatlah pertanyaan-pertanyaan ini:

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 |
+----------+

Hitungan di atas tidak cocok. Sementara sesuai pemahaman saya:

Hitung dengan IS NULL dan Hitung dengan IS NOT NULL harus sama dengan menghitung ketika ditanya tanpa klausa mana.

Adakah yang tahu apa yang terjadi di sini?

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

Pembaruan pada 17 Februari 2012

Sejak itu, saya menemukan bahwa banyak orang bertanya tentang jenis nilai yang diestimasi saat ini. Inilah jawabannya:

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)

Seperti yang Anda lihat di atas taksiran tanggal memiliki NULL atau nilai datetime yang valid. Tidak ada nol atau string kosong "".

Bisakah ini (masalah asli) terjadi jika indeks pada estim_date memiliki beberapa masalah?

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

Pembaruan pada 18 Februari 2012

Ini adalah show create output table:

 | 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 |

Sekali lagi, saya hanya dapat menduga indeks pada taksiran tanggal di sini.

Juga, versi server mysql adalah 5.5.12.

18
user1213259

Apakah Anda memiliki beberapa tanggal nol? Nilai datetime dari 0000-00-00 00:00:00 dianggap oleh MySQL untuk secara bersamaan memuaskan is null dan is not null:

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

[email protected]@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
[email protected]@localhost > select a from _tmp where a is null;
+---------------------+
| a                   |
+---------------------+
| 0000-00-00 00:00:00 |
+---------------------+
1 row in set (0.00 sec)

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

Lihat: http://bugs.mysql.com/bug.php?id=94

Ini diklasifikasikan sebagai "bukan bug". Mereka menyarankan solusi: gunakan mode ketat, yang akan mengubah peringatan penyisipan menjadi kesalahan.

Setelah mengatakan semua itu, ini saja tidak bisa menjelaskan variasi liar dalam hasil yang Anda dapatkan (jumlah is null dan is not null jumlah harus melebihi jumlah yang tidak dibatasi) ...

6
araqnid

@ypercube:

Saya baru-baru ini ditanya apakah saya pikir bug regresi "SELECT COUNT (DISTINCT) crash InnoDB ketika operan WHERE berada di Primary Key atau Unique Index" bisa menjadi akar dari ini.

Inilah jawaban saya (asal di sini):

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

Saya tidak berpikir ini adalah bug yang sama. Bug ini lebih tentang crash, dan membutuhkan SELECT COUNT (DISTINCT) khusus, ditambah operan WHERE ada di Primary Key atau indeks Unik.

Bug/masalah Anda tidak memiliki DISTINCT, itu tidak menabrak, dan indeks pada kolom datetime bukan kunci utama atau unik. Namun, ini agak aneh, jadi saya melakukan pencarian, dan menemukan bug ini, yang sepertinya lebih terlibat/terkait:

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

Sebenarnya, ini ditetapkan sebagai "bukan bug", tetapi ini menunjukkan/menggambarkan bagaimana Anda dapat mengalami perilaku aneh ketika Anda memiliki tanggal/waktu dengan '0000-00-00 ′ dan menggunakan IS NULL dan IS TIDAK NULL.

Saya ingin tahu apakah Anda memiliki baris '0000-00-00' yang dapat memengaruhi penghitungan?

Perhatikan Dev yang berkomentar dalam laporan bug menyebutkan halaman ini juga:

Jika bukan itu, saya pasti akan merekomendasikan untuk meningkatkan dan mencoba ini pada 5.5 terbaru, yaitu 5.5.21 (per 2/22/2012), karena sudah 9 bulan (dan 9 rilis) sejak 5.5.12 sudah diterbitkan.

Catatan Anda harus dapat membuang tabel (dan data) dan mengimpornya ke contoh pengujian lain, hanya untuk mengujinya. Dengan begitu Anda tidak memengaruhi mesin produksi, dan Anda dapat mengatur instans uji coba dalam hitungan menit.

Kemudian, jika itu tidak membuat perbedaan apa pun, Anda berada dalam posisi untuk menguji beberapa item lain, seperti mungkin mengonversi tabel ke MyISAM untuk melihat apakah masalahnya adalah masalah global, atau hanya khusus untuk InnoDB.

Atau, saya perhatikan indeks pada ‘Estimasi_tanggal 'adalah:

KUNCI estimated_date_index (estimated_date) MENGGUNAKAN BTREE

Perhatikan "MENGGUNAKAN BTREE". Mungkin cobalah tanpa MENGGUNAKAN BTREE dan lihat apakah Anda masih melihat perilaku yang sama. (Atau hapus indeks sekaligus hanya untuk menguji .. semuanya akan membantu mempersempit masalah).

Semoga ini membantu.

3
Chris Calender

Saya melihat sesuatu yang menarik dalam tata letak tabel yang berteriak 'Saya tidak ingin menghitung'. Apa yang akan saya katakan hanyalah firasat.

Anda menjalankan kueri ini sebelumnya

select distinct date(estimated_date) from s_p;

Jalankan sebagai COUNT/GROUP BY

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

Anda harus mendapatkan jumlah pasti yang Anda cari.

Namun, mengapa penghitungan untuk NULL dan NOT NULL dapat dihitung dengan benar? Sekali lagi, ini hanya tebakan yang berpendidikan.

Anda memiliki kolom estimated_date diindeks. Inilah yang saya ingin Anda coba:

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

Itu bukan kesalahan ketik. Saya ingin Anda menjalankan SHOW INDEX FROM s_p; empat (4) kali. Lihatlah kolom Cardinality. Karena tabel s_p di InnoDB, saya berharap kolom Kardinalitas berbeda setiap kali. Mengapa?

InnoDB mendapatkan nilai Kardinalitas dengan memperkirakannya (TIDAK ADA PUN YANG DIMAKSUDKAN) dengan menghitung melalui entri halaman BTREE. Periksa variabel sistem Anda innodb_stats_on_metadata . Itu harus diaktifkan. Jika sudah diaktifkan, nonaktifkan dan jalankan kembali pertanyaan awal Anda untuk melihat apakah ada peningkatan. LAKUKAN HAL INI SEBAGAI RESOR TERAKHIR !!!

Jadi alih-alih pertanyaan ini:

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

Mencoba

select count(estimated_date) from s_p;

Ini akan memberi Anda jumlah baris dengan taksiran tanggal null.

Pendekatan lain yang Anda mungkin ingin bereksperimen dengan permintaan brute force ini menggunakan ISNULL fungsi:

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

Saya harap saran ini membantu !!!

1
RolandoMySQLDBA

Coba kueri

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