MySQL NULL / NULL NOT Yanlış mı davranıyor?


18

Lütfen bu tabloya bakın:

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

Şimdi şu sorgulara bir göz atın:

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

Yukarıdaki sayılar eşleşmiyor. Anladığım kadarıyla:

İle say IS NULLve IS NOT NULLnerede say, nerede cümlesi olmadan sorgulandığında saymaya eşit olmalıdır.

Burada neler olduğu hakkında bir fikrin var mı?

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

17 Şubat 2012 Güncellemesi

O zamandan beri, bir çok insan şu anda tahmin edilen verilerin türünü soruyor. İşte cevap:

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)

Yukarıda da görebileceğiniz gibi tahmini_tarihi NULL veya geçerli bir tarih / saat değerlerine sahiptir. Sıfır "veya boş dize yok" ".

Tahmini_tarih dizinindeki bazı sorunlar varsa bu (orijinal sorun) olabilir mi?

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

18 Şubat 2012 Güncellemesi

İşte show create tablo çıktısı:

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

Yine, sadece tahmini_tarih tarihinde dizinden şüphelenebilirim.

Ayrıca, mysql sunucu sürümü 5.5.12'dir.


3
Tablo 3 sorgu arasında ve sırasında yeni satırlarla beslenmedikçe, bu olamaz!
ypercubeᵀᴹ

6
Yaptığınızdan emin select count(*)değil select count(estimated_date)misiniz? Saydığınız tek şey bu ise NULL'lar yok sayıldığından bu ikisi farklı sonuçlar döndürür.

6
Aşağıdakilerin MySQL'de çalışıp çalışmayacağından emin değilim, ancak çalışmayı deneyebilirsiniz: 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- tek seferde tüm sayıları almalıdır.
Damien_The_Unbeliever

1
Bunlar tam olarak çalıştırdığınız sorgular mı?
gbn

4
Ayrıca, bu MyISAM ise, üzerinde çalışabilir misiniz CHECK TABLE? Çılgınca daha büyük tam satır sayısı düşünüldüğünde, bir DELETEyerde deli gitti sanırım .
Naltharial

Yanıtlar:


6

Sıfır tarihin var mı? Tarih ve saat değerleri 0000-00-00 00:00:00MySQL tarafından eşzamanlı olarak karşılanır is nullve is 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)

Bkz. Http://bugs.mysql.com/bug.php?id=940

Bu "hata değil" olarak sınıflandırılır. Geçici bir çözüm önerirler: ekleme uyarısını hataya dönüştürecek katı mod kullanın.

Tüm bunları söyledikten sonra, bu tek başına elde ettiğiniz sonuçlardaki vahşi varyasyonu açıklayamaz ( is nullve is not nullsayılarının toplamı sınırsız sayıyı aşmalıdır) ...


Hata, DATEveya DATETIMEolarak tanımlandığında görünür NOT NULL. Buradaki soruda, sütun boş değer olarak tanımlanmıştır. Ancak bu hata, MySQL'i yalnızca katı modda çalıştırmak için başka bir nedendir.
ypercubeᵀᴹ

Tahmini_tarih sütununda geçerli değerleri göstermek için orijinal gönderi güncelledi. 0000-00-00 veya boş dizeleri "" yok.
user1213259

1
@yper veya farklı bir DBMS seçmek için bir neden ...
ErikE

1
@ErikE: Bazen bu bir seçenek değil. Ve çalıştığınız her ne olursa olsun, anotehr DBMS'yi seçmek için her zaman nedenleri bulacaksınız.
ypercubeᵀᴹ

FYI ToadSQL, 0000-00-00 00:00:00 değerini {null} olarak gösterir, suları daha da çamurluyor! Ne kabustu ama. FTR sorun sütunumuzda bir dizin yok. Bu 5.6.15 günlüğündedir.
sming

3

@ypercube:

Geçenlerde regresyon hatası "SELECT COUNT (DISTINCT), NEREDE işleneni birincil anahtar veya benzersiz dizinde olduğunda InnoDB çöküyor" bu kök olabilir düşündüm sordu.

İşte cevabım (aslında burada):

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

Bunun aynı hata olduğunu düşünmüyorum. Bu hata kilitlenme hakkında daha fazladır ve özellikle bir SELECT COUNT (DISTINCT) gerektirir, ayrıca WHERE işlenen Birincil Anahtar veya Benzersiz dizinindedir.

Hata / sorun DISTINCT yok, çöküyor ve datetime sütunundaki dizin birincil anahtar veya benzersiz değil. Ancak, manşet biraz garip, bu yüzden biraz arama yaptım ve daha fazla dahil / ilişkili olması muhtemel gibi bu hata, koştu:

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

Aslında, "hata değil" olarak adlandırılır, ancak '0000-00-00 ′ ile tarih / tarihleriniz olduğunda ve IS NULL ve IS NOT NULL kullanarak garip davranışlara nasıl girebileceğinizi gösterir / açıklar.

Sayımları etkileyebilecek bu '0000-00-00 ′ satırlarından herhangi birine sahip olup olmadığınızı merak ediyorum.

Hata raporunda yorum yapan Dev'in bu sayfadan da bahsettiğini unutmayın:

Bu değilse, kesinlikle 5.5.12'den beri 9 ay (ve 9 sürüm) olduğu için 5.5.21 (2/22/2012 itibariyle) olan en son 5.5'te yükseltmenizi ve denemenizi tavsiye ederim. serbest bırakıldı.

Yalnızca test etmek için tabloyu (ve verileri) döküp başka bir test örneğine aktarabileceğinizi unutmayın. Bu şekilde bir üretim makinesini etkilemezsiniz ve birkaç dakika içinde bir test örneğine sahip olabilirsiniz.

Daha sonra, yine de bir fark yaratmazsa, sorunun küresel bir sorun olup olmadığını veya yalnızca InnoDB'ye özgü olup olmadığını görmek için tabloyu MyISAM'e dönüştürmek gibi başka öğeleri test etme pozisyonunda olursunuz.

Veya, 'tahmini_tarihi' dizini:

BTREE KULLANIMI ANAHTAR estimated_date_index( estimated_date)

“BTREE KULLANIMI” na dikkat edin. Belki BTREE KULLANMADAN deneyin ve hala aynı davranışı görüp görmediğinizi görün. (Ya da sadece test etmek için dizini tamamen kaldırın .. hepsi sorunu daraltmaya yardımcı olacaktır).

Bu yardımcı olur umarım.


1

Sorguyu deneyin

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

Sorunun ne olduğunu anladığınızı sanmıyorum.

2
Yukarıdaki sorgu, çözümü bulabileceğiniz hatalı davranış gösteren satırları gösterir.

1
Bu sorgu herhangi bir satır döndürürse , verilerinizin bütünlüğü konusunda ciddi endişe duyarım .
Naltharial

@Nalharial Verilerim değil, yukarıdaki soru tuhaf çıktılar veriyor.

mysql> tahmini_tarihi null ve tahmini_tarihi null sınır 5 değil s_p'den * seçin; Boş set (0,00 saniye)
user1213259

1

Tablo düzeninde 'saymak istemiyorum' diye çığlık atan ilginç bir şey görüyorum. Söyleyeceğim sadece bir önsezi.

Bu sorguyu daha önce çalıştırdınız

select distinct date(estimated_date) from s_p;

COUNT / GROUP BY olarak çalıştırın

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

Aradığınız kesin sayıları alacaksınız.

Yine de, NULL ve NOT NULL sayımları neden doğru hesaplanır? Yine, bu sadece eğitimli bir tahmindir.

Sütunu estimated_datedizine eklediniz. İşte denemenizi istiyorum:

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

Bu bir yazım hatası değil. Seni koşarken istiyorum SHOW INDEX FROM s_p;dört (4) kez. CardinalitySütuna bak . s_pInnoDB'deki tablodan beri Cardinality sütununun her seferinde farklı olmasını bekliyorum. Neden?

InnoDB, BTREE sayfa girişlerini sayarak tahmin ederek Cardinality değerini alır (NO PUN INTENDED). Sistem değişkeninizi innodb_stats_on_metadata kontrol edin . Etkinleştirilmelidir. Zaten etkinse, devre dışı bırakın ve bir şeylerin iyileşip iyileşmediğini görmek için orijinal sorgularınızı yeniden çalıştırın. BU SADECE SON BİR RESORT OLARAK YAPMAK !!!

Bu sorgular yerine:

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

Deneyin

select count(estimated_date) from s_p;

Bu size, boş olmayan bir tahmin_tarihi olan satırların sayısını vermelidir.

ISNULL işlevini kullanarak bu kaba kuvvet sorgusunu denemek isteyebileceğiniz başka bir yaklaşım :

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

Umarım bu öneriler yardımcı olur !!!


-4

Bu bekleniyor. Sıfırlanabilir bir sütun için 0 == NULL = "" vb. Dolayısıyla, ilk kontrol hiçbir tarihin ayarlanmadığı veya "0 / NULL" değerine benzediği satırları döndürür


2
0asla eşit değildir NULL. Oracle ile çalışmadığınız sürece, boş dize ( '') işlevi aynı değildir NULL.
ypercubeᵀᴹ
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.