MySQLはNULLである/ NULLではない


18

次の表をご覧ください。

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

次のクエリをご覧ください。

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

上記のカウントは一致しません。私の理解によると:

Count with IS NULLおよびCount with IS NOT NULLは、where句なしで照会された場合のcountと等しくなければなりません。

ここで何が起こっているのか考えていますか?

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

2012年2月17日に更新

以来、多くの人々が現在、estimated_dateが持つ値の種類について尋ねていることがわかりました。答えは次のとおりです。

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)

上記のように、timated_dateにはNULL値または有効な日時値が含まれています。ゼロまたは空の文字列「」はありません。

expected_dateのインデックスに問題がある場合、これ(元の問題)は発生しますか?

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

2012年2月18日に更新

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 |

繰り返しになりますが、ここで推測される日付のインデックスのみが疑われます。

また、mysqlサーバーのバージョンは5.5.12です。


3
3つのクエリの実行中および実行中にテーブルに新しい行が供給されない限り、これは起こり得ません!
ypercubeᵀᴹ

6
あなたはAを行っていることを確信しているselect count(*)といませんかselect count(estimated_date)?カウントしているのがNULLだけである場合、NULLは無視されるため、これら2つは異なる結果を返します。

6
次がMySQLで機能するかどうかはわかりませんが、実行してみてください: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-一度にすべてのカウントを取得する必要があります。
-Damien_The_Unbeliever

1
これらはあなたが実行している正確なクエリですか?
gbn

4
また、これがMyISAMの場合、実行できますCHECK TABLEか?極端に大きい全行数を考慮すると、DELETEどこか狂ったように思えます。
ナルサリアル

回答:


6

日付がありませんか?日時の値が0000-00-00 00:00:00同時に満足させるためにMySQLが考えられている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)

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

これは「バグではない」として分類されます。彼らは回避策を提案します:挿入警告をエラーに変換する厳密モードを使用します。

すべてのことを言っても、これだけでは缶があなたが(の合計取得している結果で野生の変動を説明しないis nullis not null数が無制限の数を超えている必要があります)を...


バグが表示されたとき、DATEまたはDATETIMEのように定義されますNOT NULL。ここの質問では、列はヌル可能として定義されています。ただし、このバグは、厳密モードのみでMySQLを実行するもう1つの理由です。
ypercubeᵀᴹ

元の投稿を更新して、timated_date列に現在の値を表示しました。0000-00-00または空の文字列 ""はありません。
-user1213259

1
@yperまたは異なるDBMSを選択する理由...
ErikE

1
@エリク:それは、時には選択ではありません。また、使用しているものに関係なく、常にanotehr DBMSを選択する理由を見つけることができます。
ypercubeᵀᴹ

FYI ToadSQLは0000-00-00 00:00:00を{null}として表示し、さらに水を濁しています!なんて悪夢だ。FTRでは、問題のある列にインデックスがありません。これは5.6.15-logにあります。
16年

3

@ypercube:

最近、「WHEREオペランドが主キーまたは一意のインデックスにあるときにSELECT COUNT(DISTINCT)がInnoDBをクラッシュさせる」という回帰バグがこのルートにあると思われるかどうかを尋ねられました。

ここに私の返信があります(元々はここにあります):

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

これは同じバグだとは思わない。このバグはクラッシュに関するものであり、具体的にはSELECT COUNT(DISTINCT)が必要です。さらに、WHEREオペランドは主キーまたは一意のインデックスにあります。

バグ/問題にDISTINCTがなく、クラッシュしておらず、datetime列のインデックスが主キーでも一意でもありません。しかし、それはカフから少し奇妙なので、私はいくつかの検索を行いましたが、このバグに遭遇しました。

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

実際には、「バグではない」と指定されていますが、 '0000-00-00'で日付/日付時刻があり、IS NULLおよびIS NOT NULLを使用している場合に、奇妙な動作に陥る方法を示しています。

カウントに影響を与える可能性のあるこれらの「0000-00-00」行のいずれかがあるのだろうか?

バグレポートでコメントしている開発者がこのページにも言及していることに注意してください。

そうでない場合は、5.5.12から9か月(および9リリース)であるため、最新の5.5(5.5.21(2012年2月22日現在))でアップグレードして試すことをお勧めします。解放された。

テストするためだけに、テーブル(およびデータ)をダンプし、別のテストインスタンスにインポートできることに注意してください。そうすれば、実稼働マシンに影響を与えず、テストインスタンスを数分でセットアップできます。

その後、それでも違いが生じない場合は、テーブルをMyISAMに変換して、問題がグローバルなものか、InnoDBに固有のものかを確認するなど、他のアイテムをテストすることができます。

または、「estimated_date」のインデックスが次のようになっていることに気付きました。

BTREEを使用するキーestimated_date_indexestimated_date

「USING BTREE」に注意してください。USING BTREEを使用せずに試してみて、同じ動作が引き続き発生するかどうかを確認してください。(または単にテストするためにインデックスを完全に削除します..問題を絞り込むのに役立ちます)。

お役に立てれば。


1

クエリを試してください

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

質問が何であるか理解していないと思います。

2
上記のクエリは、問題のある行を表示して、そこから解決策を見つけることができます。

1
そのクエリが行を返す場合、データの整合性について真剣に心配しています。
ナルタリアル

@Naltharialそれは私のデータではなく、上の質問は奇妙な出力を与えます。

mysql> select * from s_p 空のセット(0.00秒)
-user1213259

1

テーブルレイアウトには、「私は数えたくない」と叫ぶ興味深いものがあります。私が言おうとしていることは、ほんの一握りです。

前にこのクエリを実行しました

select distinct date(estimated_date) from s_p;

COUNT / GROUP BYとして実行します

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

あなたはあなたが探していた決定的な数を得ます。

それでも、なぜNULLとNOT NULLのカウントが正しく計算されるのでしょうか?繰り返しますが、これは単なる知識に基づいた推測です。

列にestimated_dateインデックスが作成されました。ここに私があなたに試して欲しいものがあります:

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

それはタイプミスではありません。SHOW INDEX FROM s_p;4回実行してほしい。Cardinality列を見てください。s_pInnoDB のテーブルなので、Cardinality列は毎回異なると予想しています。どうして?

InnoDBは、BTREEページエントリを介してカウントすることにより、カーディナリティ値を推定します(NO PUN INTENDED)。システム変数innodb_stats_on_metadataを確認してください。有効にする必要があります。既に有効になっている場合は、無効にして元のクエリを再実行し、改善されるかどうかを確認します。これは最後の手段としてのみ行ってください!

したがって、これらのクエリの代わりに:

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

試して

select count(estimated_date) from s_p;

これにより、null以外のexpected_dateを持つ行のカウントが得られます。

ISNULL関数を使用して、このブルートフォースクエリを試すことができる別のアプローチ:

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

これらの提案が役立つことを願っています!!!


-4

これは予想されることです。ヌル可能列の場合、0 == NULL = ""など。したがって、最初のチェックは実際に日付が設定されていない行、または「0 / NULL」に類似した認識された行を返します


2
0は決して等しくなりませんNULL。空の文字列('')はNULL、Oracleで作業している場合を除き、どちらとも同じではありません。
ypercubeᵀᴹ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.