MySQL นั้นเป็นโมฆะ / ไม่เป็นโมฆะ?


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

จำนวนข้างต้นไม่ตรงกัน ในขณะที่ตามความเข้าใจของฉัน:

นับด้วยIS NULLและนับด้วยIS NOT NULLควรเท่ากับจำนวนเมื่อถูกสอบถามโดยไม่มีตำแหน่ง

ความคิดเกี่ยวกับสิ่งที่เกิดขึ้นที่นี่?

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

อัพเดทเมื่อวันที่ 17 กุมภาพันธ์ 2555

ตั้งแต่ฉันพบว่าผู้คนจำนวนมากกำลังถามเกี่ยวกับชนิดของค่าที่ประมาณโดยปัจจุบันมี นี่คือคำตอบ:

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)

ดังที่คุณเห็นข้างบนโดยประมาณ_d_dateมีค่า NULL หรือค่า datetime ที่ถูกต้อง ไม่มีเลขศูนย์หรือสตริงว่าง ""

สิ่งนี้ (ปัญหาดั้งเดิม) สามารถเกิดขึ้นได้หรือไม่ถ้าดัชนีในวันที่มีการประมาณมีบางปัญหา

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

อัพเดทเมื่อวันที่ 18 กุมภาพันธ์ 2555

นี่คือการแสดงสร้างตารางผลลัพธ์:

 | 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
คุณแน่ใจหรือไม่ว่าคุณกำลังทำselect count(*)และไม่select count(estimated_date)? ทั้งสองนี้จะให้ผลลัพธ์ที่แตกต่างกันเนื่องจาก NULL จะถูกละเว้นหากเป็นสิ่งเดียวที่คุณกำลังนับ

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ไปที่ไหนสักแห่งบ้า
Naltharial

คำตอบ:


6

คุณมีวันที่ศูนย์บ้างไหม? ค่าของวันที่และเวลา0000-00-00 00:00:00จะถูกพิจารณาโดย MySQL เพื่อตอบสนองis nullและ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)

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

สิ่งนี้จัดเป็น "ไม่ใช่บั๊ก" พวกเขาแนะนำวิธีแก้ปัญหา: ใช้โหมดเข้มงวดซึ่งจะแปลงคำเตือนการแทรกเป็นข้อผิดพลาด

ต้องบอกว่าทั้งหมดนี้เพียงอย่างเดียวไม่สามารถอธิบายความแปรปรวนในผลลัพธ์ที่คุณได้รับ (ผลรวมของis nullและis not nullจำนวนควรเกินจำนวนที่ไม่ จำกัด ) ...


ข้อผิดพลาดปรากฏขึ้นเมื่อDATEหรือถูกกำหนดให้เป็นDATETIME NOT NULLในคำถามที่นี่คอลัมน์ถูกกำหนดเป็นโมฆะ อย่างไรก็ตามข้อผิดพลาดนี้เป็นอีกสาเหตุหนึ่งที่ทำให้รัน MySQL ในโหมดเข้มงวดเท่านั้น
ypercubeᵀᴹ

ฉันได้อัปเดตโพสต์ดั้งเดิมเพื่อแสดงค่าปัจจุบันในคอลัมน์โดยประมาณ มันไม่มี 0000-00-00 หรือสตริงว่าง ""
user1213259

1
@ ปีหรือเหตุผลที่เลือก DBMS อื่น ...
ErikE

1
@ErikE: บางครั้งก็ไม่ใช่ทางเลือก และคุณจะพบเหตุผลเสมอที่จะเลือก DBMS ไม่ว่าคุณจะทำงานอะไร
ypercubeᵀᴹ

FYI ToadSQL แสดง 0000-00-00 00:00:00 ในฐานะ {null} ทำให้เกิดน้ำท่วม! ช่างฝันร้ายอะไร FTR เราไม่มีดัชนีในคอลัมน์ปัญหาของเรา นี่คือบันทึก 5.6.15
sming

3

@ypercube:

ฉันถูกถามเมื่อไม่นานมานี้ว่าฉันคิดว่าข้อผิดพลาดในการถดถอย "SELECT COUNT (DISTINCT) ขัดข้อง InnoDB เมื่อตัวถูกดำเนินการอยู่ในคีย์หลักหรือดัชนีที่ไม่ซ้ำ" อาจอยู่ที่รากของสิ่งนี้

นี่คือคำตอบของฉัน (แต่เดิมที่นี่):

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

ฉันไม่คิดว่านี่เป็นข้อผิดพลาดเดียวกัน ข้อผิดพลาดนี้เป็นข้อมูลเพิ่มเติมเกี่ยวกับการหยุดทำงานและต้องใช้ SELECT COUNT (DISTINCT) โดยเฉพาะรวมถึงตัวถูกดำเนินการที่อยู่ในคีย์หลักหรือดัชนีที่ไม่ซ้ำ

ข้อบกพร่อง / ปัญหาของคุณไม่มี DISTINCT ไม่ใช่การหยุดทำงานและดัชนีในคอลัมน์วันที่และเวลาไม่ใช่คีย์หลักหรือไม่ซ้ำกัน อย่างไรก็ตามมันค่อนข้างแปลกออกจากผ้าพันแขนดังนั้นฉันจึงทำการค้นหาและวิ่งข้ามจุดบกพร่องนี้ซึ่งดูเหมือนว่าจะเกี่ยวข้องกับ / เกี่ยวข้องมากกว่า:

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

ที่จริงแล้วมันถูกกำหนดให้เป็น“ ไม่ใช่ข้อผิดพลาด” แต่มันแสดง / อธิบายถึงวิธีที่คุณสามารถทำงานเป็นพฤติกรรมแปลก ๆ เมื่อคุณมีวันที่ / ชุดข้อมูลด้วย '0000-00-00′ และใช้ IS NULL และไม่เป็นโมฆะ

ฉันสงสัยว่าคุณมีแถว '0000-00-00 these เหล่านี้ซึ่งอาจส่งผลกระทบต่อจำนวนหรือไม่

บันทึกผู้พัฒนาที่แสดงความคิดเห็นในรายงานข้อผิดพลาดระบุถึงหน้านี้ด้วย:

หากไม่เป็นเช่นนั้นฉันขอแนะนำให้อัพเกรดและลองใช้สิ่งนี้ใน 5.5 ล่าสุดซึ่งก็คือ 5.5.21 (จนถึง 2/22/2012) เนื่องจากมันใช้เวลา 9 เดือน (และ 9 ครั้ง) นับตั้งแต่ 5.5.12 ได้รับการปล่อยตัว

หมายเหตุคุณควรจะสามารถถ่ายโอนข้อมูลตาราง (และข้อมูล) และนำเข้าสู่อินสแตนซ์ทดสอบอื่นเพื่อทดสอบ ด้วยวิธีนี้คุณจะไม่ส่งผลกระทบต่อเครื่องจักรในการผลิตและคุณสามารถตั้งค่าอินสแตนซ์ทดสอบได้ในไม่กี่นาที

จากนั้นหากที่ยังไม่สร้างความแตกต่างคุณจะอยู่ในตำแหน่งที่จะทดสอบรายการอื่น ๆ เช่นอาจแปลงตารางเป็น MyISAM เพื่อดูว่าปัญหาดังกล่าวเป็นปัญหาระดับโลกหรือเฉพาะกับ InnoDB

หรือฉันสังเกตเห็นว่าดัชนีใน 'estim_date' คือ:

KEY estimated_date_index( estimated_date) ใช้ BTREE

หมายเหตุ“ การใช้ BTREE” อาจลองใช้โดยไม่ใช้ BTREE และดูว่าคุณยังคงเห็นพฤติกรรมเดิมหรือไม่ (หรือลบดัชนีทั้งหมดเพียงเพื่อทดสอบ .. มันจะช่วยให้ปัญหาแคบลง)

หวังว่านี่จะช่วยได้


1

ลองใช้แบบสอบถาม

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

ฉันไม่คิดว่าคุณเข้าใจว่าคำถามคืออะไร

2
แบบสอบถามด้านบนจะแสดงแถวพฤติกรรมที่ไม่ถูกต้องซึ่งคุณสามารถหาวิธีแก้ปัญหาได้

1
หากแบบสอบถามนั้นส่งคืนแถวใด ๆ ฉันจะเป็นกังวลอย่างจริงจังเกี่ยวกับความถูกต้องของข้อมูลของคุณ
Naltharial

@Networkarial ไม่ใช่ข้อมูลของฉันคำถามข้างต้นให้ผลลัพธ์แปลก ๆ

mysql> select * from s_p โดยที่ appro_date เป็นโมฆะและ Est_date ไม่ จำกัด โมฆะ 5; ชุดว่าง (0.00 วินาที)
1213259

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 และ 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 ฉันคาดว่าคอลัมน์ Cardinality จะแตกต่างกันในแต่ละครั้ง ทำไม?

InnoDB รับค่า Cardinality โดยประมาณ (ไม่ PUN ตั้งใจ) โดยนับผ่านรายการหน้า 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);

ฉันหวังว่าคำแนะนำเหล่านี้จะช่วยได้ !!!


-4

สิ่งนี้คาดว่า สำหรับคอลัมน์ที่เป็นโมฆะ 0 == NULL = "" และอื่น ๆ ดังนั้นการตรวจสอบครั้งแรกจะส่งกลับแถวที่ไม่มีการตั้งค่าวันที่หรือรับรู้คล้ายกับ "0 / NULL"


2
0NULLจะไม่เท่ากับ สตริงว่าง ( '') ไม่เหมือนกันNULLเว้นแต่คุณจะทำงานกับ Oracle
ypercubeᵀᴹ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.