it-swarm.asia

MySQL IS NULL / IS NOT NULL يسيء التصرف؟

يرجى إلقاء نظرة على هذا الجدول:

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

الأعداد أعلاه غير متطابقة. بينما حسب فهمي:

نعول مع IS NULL والعد مع IS NOT NULL يجب أن تكون مساوية للعد عند الاستعلام عنها بدون شرط "أين".

أي فكرة عما يحدث هنا؟

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

تحديث في 17 فبراير 2012

منذ ذلك الحين ، وجدت أن الكثير من الناس يسألون عن نوع القيم المقدرة حاليًا. هنا الجواب:

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)

كما ترى أعلاه ، التاريخ المقدّر إما أن يحتوي على قيم فارغة أو قيمة وقت وتاريخ صالحة. لا توجد أصفار أو سلاسل فارغة "".

هل يمكن أن يحدث هذا (المشكلة الأصلية) إذا كان الفهرس الخاص بالتاريخ المُقدر يحتوي على بعض المشاكل؟

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

تحديث في 18 فبراير 2012

هنا هو إظهار إنشاء إخراج الجدول:

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

مرة أخرى ، لا يسعني إلا أن أشك في الفهرس في التاريخ المُقدر هنا.

أيضا ، إصدار خادم الخلية هو 5.5.12.

18
user1213259

هل لديك بعض التواريخ صفر؟ تعتبر قيم Datetime لـ 0000-00-00 00:00:00 بواسطة MySQL لإرضاء is null و 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)

انظر: http://bugs.mysql.com/bug.php؟id=94

تم تصنيف هذا على أنه "ليس خطأ". يقترحون حلاً: استخدم الوضع الصارم ، والذي سيحول تحذير الإدراج إلى خطأ.

بعد قول كل ذلك ، لا يمكن لهذا وحده أن يفسر الاختلاف الجامح في النتائج التي تحصل عليها (يجب أن يتجاوز مجموع is null و is not null العدد غير المقيد) ...

6
araqnid

@ ypercube:

تم سؤالي مؤخرًا عما إذا كنت أعتقد أن خطأ الانحدار "SELECT COUNT (DISTINCT) يتعطل InnoDB عندما يكون المعامل في المفتاح الأساسي أو الفهرس الفريد" يمكن أن يكون في جذر هذا.

هنا ردي (هنا في الأصل):

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

لا أعتقد أن هذا هو نفس الخطأ. يتعلق هذا الخطأ بالمزيد من الأعطال ، ويتطلب تحديد SELECT COUNT (DISTINCT) تحديدًا ، بالإضافة إلى وجود معامل WHERE في المفتاح الأساسي أو الفهرس الفريد.

لا يحتوي الخطأ/المشكلة الخاص بك على DISTINCT ، ولا يتعطل ، والفهرس الموجود في عمود التاريخ والوقت ليس مفتاحًا أساسيًا ولا فريدًا. ومع ذلك ، فإن الأمر غريب بعض الشيء عن الكفة ، لذلك قمت ببعض البحث على الرغم من ذلك ، وركضت عبر هذا الخطأ ، والذي يبدو أكثر احتمالًا للتورط/الصلة:

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

في الواقع ، تم تصنيفها على أنها "ليست خطأ" ، ولكنها توضح/تصف كيف يمكنك مواجهة سلوك غريب عندما يكون لديك تواريخ/مواعيد مع "0000-00-00 ′ واستخدام IS NULL و IS NOT NULL.

أتساءل عما إذا كان لديك أي من هذه الصفوف من 0000-00-00 which التي يمكن أن تؤثر على التهم؟

لاحظ أن Dev الذي يعلق في تقرير الخطأ يذكر هذه الصفحة أيضًا:

إذا لم يكن الأمر كذلك ، فأنا بالتأكيد أوصي بترقية وتجربة هذا على أحدث 5.5 ، وهو 5.5.21 (اعتبارًا من 2/22/2012) ، حيث مر 9 أشهر (و 9 إصدارات) منذ 5.5.12 أصدرت.

لاحظ أنه يجب أن تكون قادرًا على تفريغ الجدول (والبيانات) واستيراده في نسخة تجريبية أخرى ، فقط لاختباره. وبهذه الطريقة لن تؤثر على آلة الإنتاج ، ويمكنك إعداد نسخة تجريبية في غضون دقائق.

بعد ذلك ، إذا لم يحدث ذلك فرقًا ، فستكون في وضع يسمح لك باختبار بعض العناصر الأخرى ، مثل ربما تحويل الجدول إلى MyISAM لمعرفة ما إذا كانت المشكلة عالمية ، أو خاصة بـ InnoDB.

أو لاحظت أن فهرس "تاريخ_التاريخ" كان:

مفتاح estimated_date_index (estimated_date) استخدام BTREE

لاحظ "استخدام BTREE". ربما جربه بدون استخدام BTREE ومعرفة ما إذا كنت لا تزال ترى نفس السلوك. (أو قم بإزالة الفهرس تمامًا فقط للاختبار .. كل ذلك سيساعد على تضييق المشكلة).

أتمنى أن يساعدك هذا.

3
Chris Calender

أرى شيئًا مثيرًا للاهتمام في تخطيط الجدول يصرخ "لا أشعر برغبة في العد". ما أنا على وشك أن أقوله هو مجرد حدس.

قمت بتشغيل هذا الاستعلام من قبل

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 وليس 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_p في InnoDB ، أتوقع أن يكون عمود الكاردينال مختلفًا في كل مرة. لماذا ا؟

يحصل InnoDB على قيمة الكاردينال من خلال تقديرها (لا يتم دفعها) عن طريق العد عبر إدخالات صفحة BTREE. تحقق من متغير النظام 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;

من المفترض أن يمنحك هذا عدد الصفوف التي لها تاريخ تقديري غير فارغ.

طريقة أخرى قد ترغب في تجربتها باستخدام استعلام القوة الغاشمة باستخدام ISNULL الوظيفة:

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

آمل أن تكون هذه المساعدة الاقتراحات !!!

1
RolandoMySQLDBA

جرب الاستعلام

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