it-swarm-eu.dev

MySQL IS NULL / IS NOT NULL Fehlverhalten?)

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 nun 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 oben genannten Zählungen stimmen nicht überein. Während nach meinem Verständnis:

Zählen mit IS NULL und zähle mit IS NOT NULL sollte bei Abfrage ohne where-Klausel gleich count sein.

Irgendeine Idee, was hier passiert?

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

Update am 17. Februar 2012

Seitdem habe ich festgestellt, dass viele Leute nach den Werten fragen, die geschätztes_Datum 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 geschätzten_Datum entweder NULL oder einen gültigen Datum/Uhrzeit-Wert. Es gibt keine Nullen oder leeren Zeichenfolgen "".

Kann dies (ursprüngliches Problem) passieren, wenn der Index für das geschätzte Datum ein Problem 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 |

Auch hier kann ich nur einen Index für das geschätzte Datum vermuten.

Außerdem ist die MySQL-Serverversion 5.5.12.

18
user1213259

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

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

Dies wird als "kein Fehler" klassifiziert. Sie schlagen eine Problemumgehung vor: Verwenden Sie den strengen 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 null und is not null Anzahl sollte die uneingeschränkte Anzahl überschreiten) ...

6
araqnid

@ypercube:

Ich wurde kürzlich gefragt, ob ich denke, dass der Regressionsfehler "SELECT COUNT (DISTINCT) stürzt 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-146

Ich denke nicht, dass dies der gleiche Fehler ist. Dieser Fehler befasst sich mehr mit dem Absturz und erfordert speziell einen SELECT COUNT (DISTINCT) sowie den WHERE-Operanden 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. Es ist jedoch ein bisschen seltsam, also habe ich ein bisschen gesucht und bin auf diesen Fehler gestoßen, der eher involviert/verwandt zu sein scheint:

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/Datenzeiten mit '0000-00-00' haben und IS] verwenden NULL und IS NOT NULL.

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 im Fehlerbericht Kommentare abgibt, auch diese Seite erwähnt:

Wenn dies nicht der Fall ist, würde ich auf jeden Fall empfehlen, dies auf dem neuesten 5.5 zu aktualisieren und zu testen, nämlich 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, um sie zu testen. Auf diese Weise haben Sie keine Auswirkungen auf eine Produktionsmaschine und können innerhalb von Minuten eine Testinstanz einrichten.

Sollte dies dennoch keinen Unterschied machen, können Sie einige andere Elemente testen, z. B. die Tabelle in MyISAM konvertieren, um festzustellen, ob es sich um ein globales Problem handelt oder nur um InnoDB-spezifische Probleme.

Oder ich habe festgestellt, dass der Index für "geschätztes Datum" wie folgt lautet:

SCHLÜSSEL estimated_date_index (estimated_date) BTREE VERWENDEN

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

Hoffe das hilft.

3
Chris Calender

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

Sie haben diese Abfrage bereits 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 endgültigen Zählungen erhalten, nach denen Sie gesucht haben.

Warum sollten die Zählungen für NULL und NICHT NULL korrekt berechnet werden? Auch dies ist nur eine fundierte Vermutung.

Sie haben die Spalte estimated_date indiziert. Ich möchte, dass Sie Folgendes 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. Schauen Sie sich die Spalte Cardinality an. Da die Tabelle s_p in 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 Ihre ursprünglichen Abfragen erneut aus, um festzustellen, ob sich die Situation verbessert. TUN SIE DAS NUR ALS LETZTES RESORT !!!

Also anstelle dieser Fragen:

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 Nicht-Null-Datum geben.

Ein weiterer Ansatz, mit dem Sie möglicherweise mit dieser Brute-Force-Abfrage experimentieren möchten, indem Sie die Funktion ISNULL verwenden:

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

Ich hoffe diese Vorschläge helfen !!!

1
RolandoMySQLDBA

Versuchen Sie die Abfrage

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