MySQL IST NULL / IST NICHT NULL.

18

Bitte schauen Sie sich diese Tabelle an:

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

Schauen Sie sich jetzt diese Fragen an:

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

Die obigen Zählungen stimmen nicht überein. Während nach meinem Verständnis:

Count with IS NULLund Count with IS NOT NULLsollten gleich count sein, wenn sie ohne where-Klausel abgefragt werden.

Irgendeine Idee, was hier passiert?

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

Update am 17. Februar 2012

Seitdem habe ich festgestellt, dass viele Leute nach den Werten fragen, die estimated_date derzeit hat. Hier ist die Antwort:

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)

Wie Sie oben sehen können, hat estimated_date entweder NULL oder einen gültigen datetime-Wert. Es gibt keine Nullen oder leere Zeichenfolgen "".

Kann dies (ursprüngliches Problem) passieren, wenn der Index für Estimated_Date ein oder mehrere Probleme aufweist?

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

Update am 18. Februar 2012

Hier ist die Ausgabe von show create 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 |

Wiederum kann ich hier nur einen Index für Estimated_date vermuten.

Die Version des MySQL-Servers ist 5.5.12.

user1213259
quelle
3
Solange die Tabelle nicht zwischen und während der Ausführung der 3 Abfragen mit neuen Zeilen gespeist wird, kann dies nicht passieren!
ypercubeᵀᴹ
6
Sind Sie sicher, dass Sie ein select count(*)und nicht tun select count(estimated_date)? Diese beiden Werte geben unterschiedliche Ergebnisse zurück, da NULL-Werte ignoriert werden, wenn dies das einzige ist, was Sie zählen.
6
Ich bin nicht sicher , ob das Folgende in MySQL arbeiten, aber können Sie versuchen , ausgeführt wird : 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- die alle der Zählungen in einem Rutsch bekommen sollte.
Damien_The_Unbeliever
1
Sind dies die genauen Abfragen, die Sie ausführen?
16.
4
Wenn dies MyISAM ist, können Sie es auch ausführen CHECK TABLE? In Anbetracht der wild wachsenden Anzahl an Zeilen würde ich vermuten, dass DELETEirgendwo etwas verrückt geworden ist.
Naltharial

Antworten:

6

Hast du ein Datum von null? Datetime-Werte von 0000-00-00 00:00:00werden von MySQL als gleichzeitig befriedigend is nullund 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)

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

Dies wird als "kein Fehler" eingestuft. Sie schlagen eine Problemumgehung vor: Verwenden Sie den strikten Modus, der die Einfügewarnung in einen Fehler umwandelt.

Abgesehen davon kann dies allein nicht die wilde Variation der Ergebnisse erklären, die Sie erhalten (die Summe der is nullund is not null-Zahlen sollte die uneingeschränkte Anzahl überschreiten) ...

araqnid
quelle
Der Fehler tritt auf, wenn das DATEoder DATETIMEals definiert ist NOT NULL. In der hier gestellten Frage ist die Spalte als nullwertfähig definiert. Dieser Fehler ist jedoch ein weiterer Grund, MySQL nur im strikten Modus auszuführen.
ypercubeᵀᴹ
Ich habe den ursprünglichen Beitrag aktualisiert, um die aktuellen Werte in der Spalte "estimated_date" anzuzeigen. Es gibt keine 0000-00-00 oder leere Zeichenfolgen "".
user1213259
1
@yper oder ein Grund, ein anderes DBMS zu wählen ...
ErikE
1
@ErikE: Das ist manchmal keine Wahl. Und Sie werden immer Gründe finden, sich für ein anderes DBMS zu entscheiden, egal mit welchem ​​Sie arbeiten.
ypercubeᵀᴹ
FYI ToadSQL zeigt 0000-00-00 00:00:00 als {null} und trübt das Wasser weiter! Was ein Alptraum. FTR Wir haben keinen Index für unsere Problemspalte. Dies ist am 5.6.15-log.
Sming
3

@ypercube:

Kürzlich wurde ich gefragt, ob der Regressionsfehler "SELECT COUNT (DISTINCT) stürzt in InnoDB ab, wenn sich der Operand WHERE im Primärschlüssel oder im eindeutigen Index befindet" die Ursache dafür sein könnte.

Hier ist meine Antwort (ursprünglich hier):

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

Ich denke nicht, dass dies der gleiche Fehler ist. Dieser Fehler befasst sich eher mit dem Absturz und erfordert speziell SELECT COUNT (DISTINCT) sowie den Operanden WHERE im Primärschlüssel oder im eindeutigen Index.

Ihr Fehler / Problem hat nicht das DISTINCT, es stürzt nicht ab und der Index für die datetime-Spalte ist weder ein Primärschlüssel noch eindeutig. Allerdings ist es etwas seltsam, also habe ich ein bisschen gesucht und bin auf diesen Fehler gestoßen, der wahrscheinlich eher damit zu tun hat:

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

Eigentlich wird es als "kein Fehler" bezeichnet, aber es zeigt / beschreibt, wie Sie auf seltsames Verhalten stoßen können, wenn Sie Daten mit "0000-00-00" haben und IS NULL und IS NOT NULL verwenden.

Ich frage mich, ob Sie eine dieser '0000-00-00'-Zeilen haben, die sich auf die Anzahl auswirken könnten.

Beachten Sie, dass der Entwickler, der Kommentare im Fehlerbericht abgibt, auch diese Seite erwähnt:

Wenn dies nicht der Fall ist, würde ich auf jeden Fall empfehlen, ein Upgrade und einen Versuch mit 5.5 durchzuführen. Dies ist 5.5.21 (Stand 22.02.2012), da seit 5.5.12 9 Monate (und 9 Releases) vergangen sind wurde veröffentlicht.

Beachten Sie, dass Sie die Tabelle (und die Daten) sichern und in eine andere Testinstanz importieren können sollten, nur um sie zu testen. Auf diese Weise haben Sie keine Auswirkungen auf eine Produktionsmaschine, und Sie können eine Testinstanz in wenigen Minuten einrichten.

Sollte dies dennoch keinen Unterschied machen, können Sie einige andere Elemente testen, z. B. die Tabelle in MyISAM konvertieren, um festzustellen, ob das Problem global oder nur für InnoDB spezifisch ist.

Oder mir ist aufgefallen, dass der Index für 'estimated_date' wie folgt lautet:

KEY estimated_date_index( estimated_date) unter Verwendung von BTREE

Beachten Sie den "USING BTREE". Versuchen Sie es vielleicht ohne das USING BTREE und sehen Sie, ob Sie immer noch dasselbe Verhalten sehen. (Oder entfernen Sie den Index ganz, um ihn zu testen. All dies hilft, das Problem einzugrenzen.)

Hoffe das hilft.

Chris Kalender
quelle
1

Versuchen Sie die Abfrage

select * from s_p where estimated_date is null and estimated_date is not null limit 5;
Naveen Kumar
quelle
Ich glaube nicht, dass du verstehst, was die Frage ist.
2
Die obige Abfrage würde die fehlerhaften Zeilen anzeigen, aus denen Sie die Lösung finden können.
1
Wenn diese Abfrage Zeilen zurückgibt, würde ich mir ernsthafte Sorgen um die Integrität Ihrer Daten machen.
Naltharial
@Naltharial Es ist nicht meine Daten, Frage oben gibt seltsame Ausgabe.
mysql> wähle * aus s_p, wobei Estimated_date null und Estimated_date nicht null ist. limit 5; Leerer Satz (0,00 Sek.)
user1213259
1

Ich sehe etwas Interessantes im Tabellenlayout, das "Ich habe keine Lust zu zählen" ruft. Was ich sagen will, ist nur eine Ahnung.

Sie haben diese Abfrage zuvor ausgeführt

select distinct date(estimated_date) from s_p;

Führen Sie es als COUNT / GROUP BY aus

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

Sie sollten die definitiven Zählimpulse erhalten, die Sie suchten.

Aber warum werden die Zählungen für NULL und NOT NULL korrekt berechnet? Auch dies ist nur eine Vermutung.

Sie haben die Spalte estimated_dateindiziert. Folgendes solltest du versuchen:

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

Das ist kein Tippfehler. Ich möchte, dass du SHOW INDEX FROM s_p;vier (4) Mal rennst. Schau dir die CardinalitySäule an. Seit der Tabelle s_pin InnoDB erwarte ich, dass die Kardinalitätsspalte jedes Mal anders ist. Warum?

InnoDB erhält den Kardinalitätswert durch Schätzen (NO PUN INTENDED) durch Zählen über die BTREE-Seiteneinträge. Überprüfen Sie Ihre Systemvariable innodb_stats_on_metadata . Es sollte aktiviert sein. Wenn es bereits aktiviert ist, deaktivieren Sie es, und führen Sie die ursprünglichen Abfragen erneut aus, um zu prüfen, ob sich Verbesserungen ergeben. TUN SIE DAS NUR ALS LETZTES RESORT !!!

Anstelle dieser Abfragen:

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

Versuchen

select count(estimated_date) from s_p;

Dies sollte Ihnen die Anzahl der Zeilen mit einem geschätzten Datum ungleich Null anzeigen.

Ein anderer Ansatz, mit dem Sie möglicherweise mit dieser Brute-Force-Abfrage mithilfe der ISNULL- Funktion experimentieren möchten :

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

Ich hoffe diese Vorschläge helfen !!!

RolandoMySQLDBA
quelle
-4

Dies wird erwartet. Für eine Spalte, die nullwertfähig ist, ist eine 0 == NULL = "" und so weiter. Die erste Prüfung gibt also tatsächlich Zeilen zurück, in denen kein Datum festgelegt wurde oder deren Wahrnehmung analog zu "0 / NULL" ist.


quelle
2
0ist niemals gleich NULL. Leere Zeichenfolge ( '') ist nicht dasselbe wie NULL, es sei denn, Sie arbeiten mit Oracle.
ypercubeᵀᴹ