คุณสมบัติที่ซ่อนอยู่ของ MySQL


101

ฉันทำงานกับMicrosoft SQL Server มาหลายปีแล้ว แต่เพิ่งเริ่มใช้MySQLกับเว็บแอปพลิเคชันของฉันได้ไม่นานและฉันก็กระหายความรู้

เพื่อดำเนินการต่อกับคำถาม "คุณลักษณะที่ซ่อนอยู่" ยาวๆ ฉันต้องการทราบคุณลักษณะที่ซ่อนอยู่หรือมีประโยชน์ของ MySQL ซึ่งหวังว่าจะช่วยเพิ่มความรู้เกี่ยวกับฐานข้อมูลโอเพนซอร์สนี้

คำตอบ:


161

เมื่อคุณได้รับเงินรางวัลฉันจะแบ่งปันความลับที่ยากจะชนะของฉัน ...

โดยทั่วไปแล้ว SQL ทั้งหมดที่ฉันปรับแต่งในวันนี้จำเป็นต้องใช้การสืบค้นย่อย มาจากโลกฐานข้อมูล Oracle สิ่งที่ฉันยอมรับไม่ได้ทำงานเหมือนกันกับ MySQL และการอ่านของฉันเกี่ยวกับการปรับแต่ง MySQL ทำให้ฉันสรุปได้ว่า MySQL อยู่เบื้องหลัง Oracle ในแง่ของการเพิ่มประสิทธิภาพการสืบค้น

ในขณะที่คำค้นหาง่ายๆที่จำเป็นสำหรับแอปพลิเคชัน B2C ส่วนใหญ่อาจทำงานได้ดีสำหรับ MySQL แต่ประเภทการรายงานรวมส่วนใหญ่ที่จำเป็นสำหรับการรายงานข่าวกรองดูเหมือนว่าจะต้องมีการวางแผนเล็กน้อยและจัดระเบียบแบบสอบถาม SQL ใหม่เพื่อเป็นแนวทางให้ MySQL ดำเนินการได้เร็วขึ้น

การบริหาร:

max_connectionsคือจำนวนการเชื่อมต่อพร้อมกัน ค่าเริ่มต้นคือ 100 การเชื่อมต่อ (151 ตั้งแต่ 5.0) - น้อยมาก

บันทึก:

การเชื่อมต่อใช้หน่วยความจำและระบบปฏิบัติการของคุณอาจไม่สามารถรองรับการเชื่อมต่อได้มากนัก

MySQL ไบนารีสำหรับ Linux / x86 ช่วยให้คุณมีการเชื่อมต่อพร้อมกันได้มากถึง 4096 รายการ แต่ไบนารีที่คอมไพล์ด้วยตนเองมักมีขีด จำกัด น้อยกว่า

ตั้งค่า table_cache ให้ตรงกับจำนวนตารางที่เปิดอยู่และการเชื่อมต่อพร้อมกัน ดูค่า open_tables และหากมีการเติบโตอย่างรวดเร็วคุณจะต้องเพิ่มขนาด

บันทึก:

2 พารามิเตอร์ก่อนหน้านี้อาจต้องใช้ไฟล์ที่เปิดอยู่จำนวนมาก 20 + max_connections + table_cache * 2 เป็นค่าประมาณที่ดีสำหรับสิ่งที่คุณต้องการ MySQL บน Linux มีตัวเลือก open_file_limit ตั้งค่าขีด จำกัด นี้

หากคุณมีคำค้นหาที่ซับซ้อน sort_buffer_size และ tmp_table_size น่าจะสำคัญมาก ค่าจะขึ้นอยู่กับความซับซ้อนของการสืบค้นและทรัพยากรที่มีอยู่ แต่แนะนำให้ใช้ 4Mb และ 32Mb ตามลำดับ

หมายเหตุ: ค่าเหล่านี้เป็นค่า "ต่อการเชื่อมต่อ" ในบรรดา read_buffer_size, read_rnd_buffer_size และอื่น ๆ ซึ่งหมายความว่าค่านี้อาจจำเป็นสำหรับการเชื่อมต่อแต่ละครั้ง ดังนั้นให้พิจารณาภาระและทรัพยากรที่มีเมื่อตั้งค่าพารามิเตอร์เหล่านี้ ตัวอย่างเช่น sort_buffer_size จะถูกจัดสรรก็ต่อเมื่อ MySQL ต้องการจัดเรียง หมายเหตุ: ระวังอย่าให้หน่วยความจำหมด

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

คีย์หลัก:

สามารถมีคอลัมน์ AUTO_INCREMENT ได้เพียงคอลัมน์เดียวต่อตารางต้องจัดทำดัชนีและต้องไม่มีค่าเริ่มต้น

โดยปกติ KEY เป็นคำพ้องความหมายของ INDEX นอกจากนี้ยังสามารถระบุคีย์แอตทริบิวต์ PRIMARY KEY เป็นเพียง KEY เมื่อกำหนดในนิยามคอลัมน์ สิ่งนี้ถูกนำไปใช้เพื่อความเข้ากันได้กับระบบฐานข้อมูลอื่น

คีย์หลักเป็นดัชนีเฉพาะที่ต้องกำหนดคอลัมน์หลักทั้งหมดให้เป็นค่าว่าง

ถ้า PRIMARY KEY หรือดัชนี UNIQUE ประกอบด้วยคอลัมน์เดียวที่มีประเภทจำนวนเต็มคุณยังสามารถอ้างถึงคอลัมน์เป็น "_rowid" ในคำสั่ง SELECT

ใน MySQL ชื่อของ PRIMARY KEY คือ PRIMARY

ปัจจุบันตาราง InnoDB (v5.1?) เท่านั้นที่รองรับคีย์ต่างประเทศ

โดยปกติคุณจะสร้างดัชนีทั้งหมดที่คุณต้องการเมื่อคุณสร้างตาราง คอลัมน์ใด ๆ ที่ประกาศเป็น PRIMARY KEY, KEY, UNIQUE หรือ INDEX จะถูกจัดทำดัชนี

NULL หมายถึง "ไม่มีค่า" ในการทดสอบค่า NULL คุณไม่สามารถใช้ตัวดำเนินการเปรียบเทียบเลขคณิตเช่น =, <, หรือ <> ใช้ตัวดำเนินการ IS NULL และไม่ใช่ NULL แทน:

NO_AUTO_VALUE_ON_ZERO ระงับการเพิ่มอัตโนมัติสำหรับ 0 ดังนั้นเฉพาะ NULL เท่านั้นที่สร้างหมายเลขลำดับถัดไป โหมดนี้จะมีประโยชน์หากเก็บ 0 ไว้ในคอลัมน์ AUTO_INCREMENT ของตาราง (การเก็บ 0 ไม่ใช่วิธีปฏิบัติที่แนะนำ แต่อย่างใด)

ในการเปลี่ยนค่าของตัวนับ AUTO_INCREMENT ที่จะใช้สำหรับแถวใหม่:

ALTER TABLE mytable AUTO_INCREMENT = value; 

หรือ SET INSERT_ID = ค่า;

เว้นแต่จะระบุไว้เป็นอย่างอื่นค่าจะเริ่มต้นด้วย: 1000000 หรือระบุดังนี้:

... ) ENGINE = MyISAM DEFAULT CHARSET = latin1 AUTO_INCREMENT = 1

TIMESTAMPS:

ค่าสำหรับคอลัมน์ TIMESTAMP จะถูกแปลงจากเขตเวลาปัจจุบันเป็น UTC สำหรับการจัดเก็บและจาก UTC เป็นเขตเวลาปัจจุบันสำหรับการดึงข้อมูล

http://dev.mysql.com/doc/refman/5.1/en/timestamp.html สำหรับคอลัมน์ TIMESTAMP หนึ่งคอลัมน์ในตารางคุณสามารถกำหนดการประทับเวลาปัจจุบันเป็นค่าเริ่มต้นและค่าการอัปเดตอัตโนมัติ

สิ่งหนึ่งที่ต้องระวังเมื่อใช้หนึ่งในประเภทเหล่านี้ใน WHERE clause ที่ดีที่สุดคือทำ WHERE datecolumn = FROM_UNIXTIME (1057941242) ไม่ใช่ WHERE UNIX_TIMESTAMP (datecolumn) = 1057941242 การทำอย่างหลังจะไม่ใช้ประโยชน์จากดัชนี ในคอลัมน์นั้น

http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html

 UNIX_TIMESTAMP() 
 FROM_UNIXTIME() 
 UTC_DATE()
 UTC_TIME()
 UTC_TIMESTAMP()

ถ้าคุณแปลง datetime เป็น unix timestamp ใน MySQL:
จากนั้นเพิ่ม 24 ชั่วโมงเข้าไป:
จากนั้นแปลงกลับเป็นวันที่และเวลาจะเสียเวลาไปหนึ่งชั่วโมงอย่างน่าอัศจรรย์!

นี่คือสิ่งที่เกิดขึ้น เมื่อแปลงการประทับเวลาของยูนิกซ์กลับเป็นวันที่และเวลาจะมีการพิจารณาเขตเวลาและมันก็เกิดขึ้นระหว่างวันที่ 28 ถึงวันที่ 29 ตุลาคม 2549 เราได้หยุดเวลาออมแสงและหายไปหนึ่งชั่วโมง

เริ่มต้นด้วย MySQL 4.1.3 ฟังก์ชัน CURRENT_TIMESTAMP (), CURRENT_TIME (), CURRENT_DATE () และ FROM_UNIXTIME () จะส่งคืนค่าในเขตเวลาปัจจุบันของการเชื่อมต่อซึ่งพร้อมใช้งานเป็นค่าของตัวแปรระบบ time_zone นอกจากนี้ UNIX_TIMESTAMP () ยังถือว่าอาร์กิวเมนต์เป็นค่าวันที่และเวลาในเขตเวลาปัจจุบัน

การตั้งค่าเขตเวลาปัจจุบันไม่มีผลกับค่าที่แสดงโดยฟังก์ชันเช่น UTC_TIMESTAMP () หรือค่าในคอลัมน์ DATE, TIME หรือ DATETIME

หมายเหตุ: ในการอัปเดตเท่านั้นอัปเดต DateTime หากฟิลด์มีการเปลี่ยนแปลงหากการอัปเดตส่งผลให้ไม่มีการเปลี่ยนแปลงฟิลด์ DateTime จะไม่อัปเดต!

นอกจากนี้ TIMESTAMP แรกคือ AUTOUPDATE ตามค่าเริ่มต้นเสมอแม้ว่าจะไม่ได้ระบุไว้ก็ตาม

เมื่อทำงานกับ Dates ฉันมักจะคิดว่า Julian Date เพราะคณิตศาสตร์ข้อมูลเป็นเรื่องง่ายๆในการเพิ่มหรือลบจำนวนเต็มและวินาทีนับตั้งแต่เที่ยงคืนด้วยเหตุผลเดียวกัน เป็นเรื่องยากที่ฉันต้องการเวลาในการปรับสภาพให้ละเอียดกว่าวินาที

ทั้งสองนี้สามารถจัดเก็บเป็นจำนวนเต็ม 4 ไบต์และถ้าพื้นที่แน่นมากสามารถรวมเป็นเวลา UNIX (วินาทีนับตั้งแต่ยุค 1/1/1970) เป็นจำนวนเต็มที่ไม่ได้ลงนามซึ่งจะใช้ได้ดีจนถึงประมาณ 2106 เป็น:

'วินาทีใน 24 ชั่วโมง = 86400

'Signed Integer max val = 2,147,483,647 - สามารถถือได้ 68 ปีวินาที

'Unsigned Integer max val = 4,294,967,295 - สามารถเก็บได้ 136 ปีวินาที

ไบนารีโปรโตคอล:

MySQL 4.1 เปิดตัวโปรโตคอลไบนารีที่อนุญาตให้ส่งและส่งคืนค่าข้อมูลที่ไม่ใช่สตริงในรูปแบบดั้งเดิมโดยไม่ต้องแปลงเป็นและจากรูปแบบสตริง (มีประโยชน์มาก)

นอกจากนี้ mysql_real_query () เร็วกว่า mysql_query () เนื่องจากไม่เรียกใช้ strlen () เพื่อดำเนินการกับสตริงคำสั่ง

http://dev.mysql.com/tech-resources/articles/4.1/prepared-statements.html โปรโตคอลไบนารีสนับสนุนคำสั่งที่เตรียมไว้ทางฝั่งเซิร์ฟเวอร์และอนุญาตให้ส่งค่าข้อมูลในรูปแบบดั้งเดิม โปรโตคอลไบนารีได้รับการแก้ไขเล็กน้อยในช่วงก่อนหน้านี้ของ MySQL 4.1

คุณสามารถใช้มาโคร IS_NUM () เพื่อทดสอบว่าเขตข้อมูลมีประเภทตัวเลขหรือไม่ ส่งผ่านค่าประเภทเป็น IS_NUM () และประเมินเป็น TRUE หากฟิลด์เป็นตัวเลข:

สิ่งหนึ่งที่ควรทราบก็คือข้อมูลไบนารีสามารถส่งภายในแบบสอบถามปกติได้หากคุณหลีกเลี่ยงมันและจำไว้ว่า MySQL ต้องการเพียงเครื่องหมายแบ็กสแลชนั้นและอักขระเครื่องหมายคำพูดเท่านั้นที่จะหลีกเลี่ยงได้ นั่นเป็นวิธีที่ง่ายมากในการแทรกสตริงไบนารีที่สั้นกว่าเช่นรหัสผ่านที่เข้ารหัส / เกลือ

เซิร์ฟเวอร์หลัก:

http://www.experts-exchange.com/Database/MySQL/Q_22967482.html

http://www.databasejournal.com/features/mysql/article.php/10897_3355201_2

GRANT จำลองแบบทาส เป็น slave_user ระบุโดย 'slave_password'

#Master Binary Logging Config  STATEMENT causes replication 
              to be statement-based -  default

log-bin=Mike
binlog-format=STATEMENT
server-id=1            
max_binlog_size = 10M
expire_logs_days = 120    


#Slave Config
master-host=master-hostname
master-user=slave-user
master-password=slave-password
server-id=2

ไฟล์บันทึกไบนารีต้องอ่าน:

http://dev.mysql.com/doc/refman/5.0/th/binary-log.html

http://www.mydigitallife.info/2007/10/06/how-to-read-mysql-binary-log-files-binlog-with-mysqlbinlog/

http://dev.mysql.com/doc/refman/5.1/en/mysqlbinlog.html

http://dev.mysql.com/doc/refman/5.0/th/binary-log.html

http://dev.mysql.com/doc/refman/5.1/en/binary-log-setting.html

คุณสามารถลบไฟล์บันทึกไบนารีทั้งหมดด้วยคำสั่ง RESET MASTER หรือส่วนย่อยของไฟล์เหล่านั้นด้วย PURGE MASTER

--result-file = binlog.txt TrustedFriend-bin.000030

นอร์มัลไลเซชัน:

http://dev.mysql.com/tech-resources/articles/intro-to-normalization.html

ฟังก์ชัน UDF

http://www.koders.com/cpp/fid10666379322B54AD41AEB0E4100D87C8CDDF1D8C.aspx

http://souptonuts.sourceforge.net/readme_mysql.htm

ประเภทข้อมูล:

http://dev.mysql.com/doc/refman/5.1/en/storage-requirements.html

http://www.informit.com/articles/article.aspx?p=1238838&seqNum=2

http://bitfilm.net/2008/03/24/saving-bytes-efficient-data-storage-mysql-part-1/

สิ่งหนึ่งที่ควรทราบคือบนโต๊ะผสมที่มีทั้ง CHAR และ VARCHAR mySQL จะเปลี่ยน CHAR เป็นของ VARCHAR

RecNum integer_type UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (RecNum)

MySQL แสดงวันที่กับปีแรกเสมอตามข้อกำหนดมาตรฐานของ SQL และ ISO 8601

อื่น ๆ:

การปิดฟังก์ชัน MySQl บางอย่างจะส่งผลให้ไฟล์ข้อมูลมีขนาดเล็กลงและเข้าถึงได้เร็วขึ้น ตัวอย่างเช่น:

--datadir จะระบุไดเร็กทอรีข้อมูลและ

--skip-innodb จะปิดตัวเลือก inno และช่วยคุณประหยัด 10-20M

เพิ่มเติมที่นี่ http://dev.mysql.com/tech-resources/articles/mysql-c-api.html

ดาวน์โหลดบทที่ 7 - ฟรี

InnoDB เป็นธุรกรรม แต่มีค่าใช้จ่ายด้านประสิทธิภาพที่มาพร้อมกับมัน ฉันพบว่าตาราง MyISAM เพียงพอสำหรับ 90% ของโครงการของฉัน ตารางที่ไม่ปลอดภัยในการทำธุรกรรม (MyISAM) มีข้อดีหลายประการซึ่งทั้งหมดนี้เกิดขึ้นเนื่องจาก:

ไม่มีค่าใช้จ่ายในการทำธุรกรรม:

เร็วขึ้นมาก

ความต้องการพื้นที่ดิสก์ลดลง

ต้องใช้หน่วยความจำน้อยลงในการอัปเดต

ตาราง MyISAM แต่ละตารางจะถูกเก็บไว้ในดิสก์ในสามไฟล์ ไฟล์มีชื่อที่ขึ้นต้นด้วยชื่อตารางและมีนามสกุลเพื่อระบุประเภทไฟล์ ไฟล์. frm เก็บรูปแบบตาราง ไฟล์ข้อมูลมีนามสกุล. MYD (MYData) ไฟล์ดัชนีมีนามสกุล. MYI (MYIndex)

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

เคล็ดลับคือทำสำเนาไฟล์เหล่านี้แล้ววางตาราง เมื่อคุณใส่ไฟล์กลับ MySQl จะจดจำและอัปเดตการติดตามตาราง

หากคุณต้องสำรอง / กู้คืน

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

SET AUTOCOMMIT = 0;
SET FOREIGN_KEY_CHECKS=0;

.. your dump file ..

SET FOREIGN_KEY_CHECKS = 1;
COMMIT;
SET AUTOCOMMIT = 1;

หากต้องการเพิ่มความเร็วในการโหลดซ้ำให้เพิ่มคำสั่ง SQL SET AUTOCOMMIT = 0; ที่จุดเริ่มต้นของไฟล์ดัมพ์และเพิ่ม COMMIT คำสั่งไปยังจุดสิ้นสุด

โดยค่าเริ่มต้น autocommit จะเปิดอยู่ซึ่งหมายความว่าคำสั่งแทรกแต่ละคำสั่งในไฟล์ดัมพ์จะถือว่าเป็นธุรกรรมแยกกันและเขียนลงดิสก์ก่อนที่จะเริ่มต้นรายการถัดไป หากคุณไม่เพิ่มคำสั่งเหล่านี้การโหลดฐานข้อมูลขนาดใหญ่เข้าไปใน InnoDB อาจใช้เวลาหลายชั่วโมง ...

ขนาดสูงสุดของแถวในตาราง MySQL คือ 65,535 ไบต์

ความยาวสูงสุดที่มีประสิทธิภาพของ VARCHAR ใน MySQL 5.0.3 และบน = ขนาดแถวสูงสุด (65,535 ไบต์)

ค่า VARCHAR จะไม่ถูกเพิ่มเมื่อมีการจัดเก็บ ช่องว่างต่อท้ายจะถูกเก็บไว้เมื่อมีการจัดเก็บและเรียกคืนค่าโดยสอดคล้องกับ SQL มาตรฐาน

ค่า CHAR และ VARCHAR ใน MySQL จะถูกเปรียบเทียบโดยไม่คำนึงถึงช่องว่างต่อท้าย

การใช้ CHAR จะทำให้การเข้าถึงของคุณเร็วขึ้นก็ต่อเมื่อบันทึกทั้งหมดมีขนาดคงที่ นั่นคือถ้าคุณใช้ออบเจ็กต์ขนาดตัวแปรใด ๆ คุณอาจสร้างขนาดตัวแปรทั้งหมดได้เช่นกัน คุณไม่ได้รับความเร็วโดยใช้ CHAR ในตารางที่มี VARCHAR ด้วย

ขีด จำกัด VARCHAR ที่ 255 อักขระถูกเพิ่มขึ้นเป็น 65535 อักขระจาก MySQL 5.0.3

รองรับการค้นหาข้อความแบบเต็มสำหรับตาราง MyISAM เท่านั้น

http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html

คอลัมน์ BLOB ไม่มีชุดอักขระและการเรียงลำดับและการเปรียบเทียบจะขึ้นอยู่กับค่าตัวเลขของไบต์ในค่าคอลัมน์

หากไม่ได้เปิดใช้งานโหมด SQL ที่เข้มงวดและคุณกำหนดค่าให้กับคอลัมน์ BLOB หรือ TEXT ที่เกินความยาวสูงสุดของคอลัมน์ค่าจะถูกตัดให้พอดีและมีการสร้างคำเตือน

คำสั่งที่เป็นประโยชน์:

ตรวจสอบโหมดที่เข้มงวด: SELECT @@ global.sql_mode;

ปิดโหมดเข้มงวด:

SET @@ global.sql_mode = '';

SET @@ global.sql_mode = 'MYSQL40'

หรือลบ: sql-mode = "STRICT_TRANS_TABLES, ...

แสดงคอลัมน์จาก mytable

เลือกสูงสุด (จำนวนชื่อ) virtualcolumnจาก mytable ORDER BY virtualcolumn

http://dev.mysql.com/doc/refman/5.0/en/group-by-hidden-fields.html

http://dev.mysql.com/doc/refman/5.1/en/information-functions.html#function_last-insert-id last_insert_id ()

ทำให้คุณได้รับ PK ของแถวสุดท้ายที่แทรกในเธรดปัจจุบันสูงสุด (pkcolname) ทำให้คุณได้รับ PK ล่าสุดโดยรวม

หมายเหตุ: ถ้าตารางว่างเปล่า max (pkcolname) จะส่งคืน 1 mysql_insert_id () จะแปลงประเภทการส่งคืนของฟังก์ชัน MySQL C API ดั้งเดิม mysql_insert_id () เป็นประเภท long (ชื่อ int ใน PHP)

ถ้าคอลัมน์ AUTO_INCREMENT ของคุณมีประเภทคอลัมน์เป็น BIGINT ค่าที่ส่งคืนโดย mysql_insert_id () จะไม่ถูกต้อง ให้ใช้ฟังก์ชัน MySQL SQL ภายใน LAST_INSERT_ID () ในแบบสอบถาม SQL แทน

http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id

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

Unknown column the first bit of data what you want to put into the table in field list

โดยใช้สิ่งที่ชอบ

INSERT INTO table (this, that) VALUES ($this, $that)

เป็นเพราะคุณไม่มีเครื่องหมายอะพอสทรอฟีรอบค่าที่คุณพยายามจะยึดติดในตาราง ดังนั้นคุณควรเปลี่ยนรหัสของคุณเป็น:

INSERT INTO table (this, that) VALUES ('$this', '$that') 

เตือนว่า `` ใช้เพื่อกำหนดฟิลด์ MySQL ฐานข้อมูลหรือตารางไม่ใช่ค่า;)

ขาดการเชื่อมต่อกับเซิร์ฟเวอร์ระหว่างการสืบค้น:

http://dev.mysql.com/doc/refman/5.1/en/gone-away.html

http://dev.mysql.com/doc/refman/5.1/en/packet-too-large.html

http://dev.mysql.com/doc/refman/5.0/en/server-parameters.html

http://dev.mysql.com/doc/refman/5.1/en/show-variables.html

http://dev.mysql.com/doc/refman/5.1/en/option-files.html

http://dev.mysql.com/doc/refman/5.1/en/error-log.html

การปรับแต่งแบบสอบถาม

http://www.artfulsoftware.com/infotree/queries.php?&bw=1313

นั่นน่าจะเพียงพอสำหรับการรับโบนัสที่ฉันคิดว่า ... ผลของเวลาหลายชั่วโมงและหลายโครงการพร้อมฐานข้อมูลฟรีที่ยอดเยี่ยม ฉันพัฒนาเซิร์ฟเวอร์ข้อมูลแอปพลิเคชันบนแพลตฟอร์ม windows ส่วนใหญ่ใช้ MySQL สิ่งที่แย่ที่สุดที่ฉันต้องทำให้ตรงคือ

สุดยอดฐานข้อมูล MySQL ฝันร้าย

สิ่งนี้จำเป็นต้องมีชุดแอปพลิเคชันเพื่อประมวลผลตารางให้เป็นสิ่งที่มีประโยชน์โดยใช้เทคนิคต่างๆที่กล่าวถึงที่นี่

หากคุณพบว่าสิ่งนี้ช่วยได้มากแสดงความขอบคุณด้วยการโหวต

ตรวจสอบบทความและเอกสารไวท์เปเปอร์อื่น ๆ ของฉันได้ที่ www.coastrd.com


22

หนึ่งในคุณสมบัติที่ไม่ได้ซ่อนอยู่ของ MySQL คือมันไม่ดีจริง ๆ ที่เป็นไปตาม SQL ได้ดีไม่ใช่บั๊ก แต่gotchasมากกว่า... :-)


การแจ้งให้คนอื่นทราบว่ารายการนี้มีค่าเมื่อย้ายจาก MSSQL ไปยัง MySQL ไชโยจ้า.
GateKiller

gotchas เหล่านี้จำนวนมากมาจาก MySQL เวอร์ชันก่อนหน้า
jmucchiello

สำหรับหนึ่งฉันไม่คิดว่าจะสามารถใส่ค่า NULL ในฟิลด์การประทับเวลาได้
จ้า

3
MySQL ไม่ได้แย่ลงโดยเฉพาะอย่างยิ่งในการทำงานร่วมกับ SQL ฐานข้อมูลอื่น ๆ ตราบเท่าที่คุณยึดติดกับชุดย่อยที่มีเหตุผลของ SQL คุณสามารถหลีกเลี่ยง gotchas ได้โดยทั่วไปซึ่งมีมากกว่าที่สามารถพูดได้เช่น สตริงว่างเปล่า NULL ที่น่าอับอายของ Oracle
Bobince

1
คุณสามารถปิดการใช้งาน gotchas บางส่วนได้SET SESSION sql_mode='ANSI';
Kornel


15

คำสั่งเพื่อค้นหาว่าใครกำลังทำอะไร:

mysql> show processlist;
show processlist;
+----+-------------+-----------------+------+---------+------+----------------------------------+------------------+
| Id | User        | Host            | db   | Command | Time | State                            | Info             |
+----+-------------+-----------------+------+---------+------+----------------------------------+------------------+
|  1 | root        | localhost:32893 | NULL | Sleep   |    0 |                                  | NULL             |
|  5 | system user |                 | NULL | Connect |   98 | Waiting for master to send event | NULL             |
|  6 | system user |                 | NULL | Connect | 5018 | Reading event from the relay log | NULL             |
+-----+------+-----------+---------+---------+-------+-------+------------------+
3 rows in set (0.00 sec) 

และคุณสามารถฆ่ากระบวนการด้วย:

mysql>kill 5 

5
แสดงรายการประมวลผลแบบเต็มหากคุณไม่ต้องการให้ข้อความค้นหาถูกตัดทอน
Greg

11

ฉันชอบการสนับสนุนในตัวของ MySQL inet_ntoa()และinet_aton(). ทำให้การจัดการที่อยู่ IP ในตารางตรงไปตรงมามาก (อย่างน้อยก็ตราบเท่าที่เป็นเพียงที่อยู่ IPv4!)


2
PostgreSQL มีประเภท inet ที่ดีมากซึ่งจัดการกับ ipv4 และ ipv6 ได้ดีมาก :-)
เสื่อ

ฉันเคยชอบพวกเขาเหมือนกัน แต่ไม่ต้องใช้เลยจะดีกว่า +1 สำหรับ Postgres
Kornel

11

ฉันชอบon duplicate key(AKA เพิ่มขึ้นรวม) สำหรับเคาน์เตอร์ทุกประเภทที่สร้างขึ้นอย่างเกียจคร้าน:

insert into occurances(word,count) values('foo',1),('bar',1) 
  on duplicate key cnt=cnt+1

คุณสามารถแทรกหลายแถวในแบบสอบถามเดียวและจัดการดัชนีที่ซ้ำกันสำหรับแต่ละแถวได้ทันที


10

อีกครั้ง - ไม่ใช่คุณสมบัติที่ซ่อนอยู่ แต่มีประโยชน์จริงๆ:

ลักษณะเฉพาะ

คว้า DDL ได้อย่างง่ายดาย:

SHOW CREATE TABLE CountryLanguage

เอาต์พุต:

CountryLanguage | CREATE TABLE countrylanguage (
  CountryCode char(3) NOT NULL DEFAULT '',
  Language char(30) NOT NULL DEFAULT '',
  IsOfficial enum('T','F') NOT NULL DEFAULT 'F',
  Percentage float(4,1) NOT NULL DEFAULT '0.0',
  PRIMARY KEY (CountryCode,Language)
) ENGINE=MyISAM DEFAULT CHARSET=latin1

คุณลักษณะ: GROUP_CONCAT () ฟังก์ชันการรวม สร้างสตริงที่ต่อกันของอาร์กิวเมนต์ต่อรายละเอียดและรวมเข้าด้วยกันโดยการเชื่อมต่อสิ่งเหล่านั้นต่อกลุ่ม

ตัวอย่างที่ 1: ง่าย

SELECT   CountryCode
,        GROUP_CONCAT(Language) AS List
FROM     CountryLanguage
GROUP BY CountryCode             

เอาท์พุต:

+-------------+------------------------------------+
| CountryCode | List                               |
+-------------+------------------------------------+
| ABW         | Dutch,English,Papiamento,Spanish   |
. ...         . ...                                .
| ZWE         | English,Ndebele,Nyanja,Shona       |
+-------------+------------------------------------+

ตัวอย่างที่ 2: หลายอาร์กิวเมนต์

SELECT   CountryCode
,        GROUP_CONCAT(
             Language
,            IF(IsOfficial='T', ' (Official)', '')
         )               AS List
FROM     CountryLanguage
GROUP BY CountryCode

เอาท์พุต:

+-------------+---------------------------------------------+
| CountryCode | List                                        |
+-------------+---------------------------------------------+
| ABW         | Dutch (Official),English,Papiamento,Spanish |
. ...         . ...                                         .
| ZWE         | English (Official),Ndebele,Nyanja,Shona     |
+-------------+---------------------------------------------+

ตัวอย่างที่ 3: การใช้ตัวคั่นแบบกำหนดเอง

SELECT   CountryCode
,        GROUP_CONCAT(Language SEPARATOR ' and ') AS List
FROM     CountryLanguage
GROUP BY CountryCode

เอาท์พุต:

+-------------+----------------------------------------------+
| CountryCode | List                                         |
+-------------+----------------------------------------------+
| ABW         | Dutch and English and Papiamento and Spanish |
. ...         . ...                                          .
| ZWE         | English and Ndebele and Nyanja and Shona     |
+-------------+----------------------------------------------+

ตัวอย่างที่ 4: การควบคุมลำดับขององค์ประกอบรายการ

SELECT   CountryCode
,        GROUP_CONCAT(
         Language
         ORDER BY CASE IsOfficial WHEN 'T' THEN 1 ELSE 2 END DESC
         ,        Language
         )               AS List
FROM     CountryLanguage
GROUP BY CountryCode

เอาท์พุต:

+-------------+------------------------------------+
| CountryCode | List                               |
+-------------+------------------------------------+
| ABW         | English,Papiamento,Spanish,Dutch,  |
. ...         . ...                                .
| ZWE         | Ndebele,Nyanja,Shona,English       |
+-------------+------------------------------------+

คุณลักษณะ: COUNT (DISTINCT) ที่มีหลายนิพจน์

คุณสามารถใช้หลายนิพจน์ในนิพจน์ COUNT (DISTINCT ... ) เพื่อนับจำนวนชุดค่าผสม

SELECT COUNT(DISTINCT CountryCode, Language) FROM CountryLanguage

คุณลักษณะ / Gotcha: ไม่จำเป็นต้องรวมนิพจน์ที่ไม่ได้รวมไว้ในรายการ GROUP BY

RDBMS-es ส่วนใหญ่บังคับใช้ GROUP ที่เข้ากันได้กับ SQL92 ซึ่งต้องการนิพจน์ที่ไม่รวมทั้งหมดในรายการ SELECT เพื่อให้ปรากฏใน GROUP BY ใน RDBMS-es เหล่านี้คำสั่งนี้:

SELECT     Country.Code, Country.Continent, COUNT(CountryLanguage.Language)
FROM       CountryLanguage 
INNER JOIN Country 
ON         CountryLanguage.CountryCode = Country.Code
GROUP BY   Country.Code

ไม่ถูกต้องเนื่องจากรายการ SELECT มีคอลัมน์ที่ไม่ได้รวม Country.Continent ซึ่งไม่ปรากฏในรายการ GROUP BY ใน RDBMS-es เหล่านี้คุณต้องแก้ไขรายการ GROUP BY เพื่ออ่าน

GROUP BY   Country.Code, Country.Continent

หรือคุณต้องเพิ่มการรวมที่ไม่รู้สึกบางอย่างให้กับ Country.Continent เป็นต้น

SELECT     Country.Code, MAX(Country.Continent), COUNT(CountryLanguage.Language)

ตอนนี้สิ่งที่เป็นเหตุผลไม่มีอะไรที่เรียกร้องให้ประเทศนั้น ๆ ทวีปควรได้รับการแก้ไข โปรดดู Country.Code เป็นคีย์หลักของตาราง Country Country.Continent เป็นคอลัมน์จากตาราง Country ด้วยดังนั้นคำจำกัดความตามหน้าที่ขึ้นอยู่กับคีย์หลัก Country.Code ดังนั้นจะต้องมีอยู่หนึ่งค่าในประเทศทวีปสำหรับแต่ละประเทศที่แตกต่างกันรหัส หากคุณตระหนักว่ามากกว่าที่คุณจะตระหนักว่ามันไม่สมเหตุสมผลที่จะรวมมัน (มีเพียงค่าเดียวใช่ไหม) หรือจัดกลุ่มตามนั้น (เพราะมันจะไม่ทำให้ผลลัพธ์มีเอกลักษณ์มากขึ้นเมื่อคุณจัดกลุ่มโดยเปิด pk)

อย่างไรก็ตาม - MySQL ช่วยให้คุณรวมคอลัมน์ที่ไม่ได้รวมไว้ในรายการ SELECT โดยไม่ต้องให้คุณเพิ่มลงใน GROUP BY clause

gotcha นี้คือ MySQL ไม่ได้ปกป้องคุณในกรณีที่คุณใช้คอลัมน์ที่ไม่ได้รวม ดังนั้นคำถามเช่นนี้:

SELECT     Country.Code, COUNT(CountryLanguage.Language), CountryLanguage.Percentage
FROM       CountryLanguage 
INNER JOIN Country 
ON         CountryLanguage.CountryCode = Country.Code
GROUP BY   Country.Code

จะดำเนินการโดยไม่มีการร้องเรียน แต่คอลัมน์ CountryLanguage.Percentage จะมีความไม่สมเหตุสมผล (กล่าวคือเปอร์เซ็นต์ของภาษาทั้งหมดค่าหนึ่งในค่าที่ใช้ได้สำหรับเปอร์เซ็นต์จะถูกเลือกโดยสุ่มหรืออย่างน้อยก็อยู่นอกการควบคุมของคุณ

ดู: Debunking Group By Myths


การอนุญาตให้คอลัมน์ที่ไม่ได้ประกาศในกลุ่มเป็นหนึ่งในคุณสมบัติที่ฉันชอบน้อยที่สุดที่มาจาก Oracle มันเป็น gotcha ที่ยิ่งใหญ่ถ้าคุณคุ้นเคยกับ Oracle - เพียงแค่ให้คุณเรียกใช้แบบสอบถามผลลัพธ์ก็ดูถูกต้อง แต่แล้วคุณก็รู้ว่ามันไม่ได้ทำอย่างที่คุณคิด
mbafford

7

คำสั่ง "เพจเจอร์" ในไคลเอนต์

หากคุณมีเช่น 10,000 แถวในผลลัพธ์ของคุณและต้องการดู (สิ่งนี้ถือว่ามีคำสั่ง "less" และ "tee" ซึ่งโดยปกติจะเป็นกรณีของ Linux ใน Windows YMMV)

pager less
select lots_of_stuff FROM tbl WHERE clause_which_matches_10k_rows;

และคุณจะได้รับไฟล์เหล่านี้ในโปรแกรมดูไฟล์ "น้อยกว่า" เพื่อให้คุณสามารถเลื่อนดูได้อย่างสวยงามค้นหาและอื่น ๆ

นอกจากนี้

pager tee myfile.txt
select a_few_things FROM tbl WHERE i_want_to_save_output_to_a_file;

สะดวกจะเขียนลงไฟล์


น่าเสียดายที่ภายใต้หน้าต่างแม้ว่าจะมี "less" และ "tee" อยู่ แต่ก็ไม่รองรับตัวเลือกเพจเจอร์เอง ไม่ใช่เรื่องง่ายอยู่ดี
Berry Tsakala

6

บางสิ่งที่คุณอาจสนใจ:

<query>\G -- \G in the CLI instead of the ; will show one column per row
explain <query>; -- this will show the execution plan for the query


3

นี่คือเคล็ดลับบางส่วนของฉัน - ฉันบล็อกเกี่ยวกับพวกเขาในบล็อกของฉัน ( ลิงก์ )

  1. คุณไม่จำเป็นต้องใช้เครื่องหมาย "@" เมื่อประกาศตัวแปร
  2. คุณต้องใช้ตัวคั่น (ค่าเริ่มต้นคือ ';') เพื่อกำหนดจุดสิ้นสุดของคำสั่ง - ลิงก์
  3. หากคุณพยายามที่จะย้ายข้อมูลระหว่าง MS-SQL 2005 และ mySQL มีห่วงสองสามอย่างที่จะข้ามผ่าน - ลิงก์
  4. ทำการจับคู่แบบตรงตามตัวพิมพ์เล็กและใหญ่ใน mySQL - ลิงก์


3

หากใช้ cmdline Mysq คุณสามารถโต้ตอบกับบรรทัดคำสั่ง (บนเครื่อง Linux - ไม่แน่ใจว่ามีผลเทียบเท่ากับ Windows หรือไม่) โดยใช้เครื่องหมาย shriek / exclamation ตัวอย่างเช่น:

\! cat file1.sql

จะแสดงรหัสสำหรับ file1.sql ในการบันทึกคำสั่งและแบบสอบถามของคุณลงในไฟล์ให้ใช้สิ่งอำนวยความสะดวกที

\T filename

เพื่อปิดการใช้งานนี้

สุดท้ายในการเรียกใช้สคริปต์ที่คุณบันทึกไว้แล้วให้ใช้ "ชื่อไฟล์ต้นฉบับ" แน่นอนทางเลือกปกติคือการกำหนดชื่อสคริปต์เมื่อเริ่ม mysql จากบรรทัดคำสั่ง:

    mysql -u root -p < case1.sql

หวังว่าจะมีประโยชน์กับใครบางคน!

แก้ไข: เพิ่งจำอีกอันหนึ่ง - เมื่อเรียกใช้ mysql จากบรรทัดคำสั่งคุณสามารถใช้สวิตช์ -t เพื่อให้เอาต์พุตอยู่ในรูปแบบตารางซึ่งเป็นประโยชน์อย่างแท้จริงกับการสืบค้นบางอย่าง (แม้ว่าแน่นอนว่าจะยุติการสืบค้นด้วย \ G ตามที่กล่าวไว้ที่อื่นที่นี่ก็เช่นกัน เป็นประโยชน์ในแง่นี้) อีกมากมายบนสวิตช์ต่างๆ Command Line Tool

เพิ่งค้นพบวิธีที่เป็นระเบียบในการเปลี่ยนลำดับของการจัดเรียง (โดยปกติใช้ Case ... ) หากคุณต้องการเปลี่ยนลำดับของการจัดเรียง (อาจเรียงลำดับด้วย 1, 4, 3, 2 แทนที่จะเป็น 1, 2, 3 4) คุณสามารถใช้ฟังก์ชันฟิลด์ภายใน Order by clause ตัวอย่างเช่น

เรียงตามฟิลด์ (sort_field, 1,4,3,2)


3

ฉันไม่คิดว่านี่เป็น MySQL เฉพาะ แต่ให้ความกระจ่างสำหรับฉัน:

แทนที่จะเขียน

WHERE (x.id > y.id) OR (x.id = y.id AND x.f2 > y.f2) 

คุณสามารถเขียน

WHERE (x.id, x.f2) > (y.id, y.f2)

มันเจ๋งมาก แต่บางกรณีจะใช้อะไรได้บ้าง?
mangoDrunk

อาจเป็นประโยชน์สำหรับการค้นหาระเบียนทั้งหมดที่มีขนาดใหญ่กว่าระเบียนที่กำหนด
Fantius

2

mysqlsla - หนึ่งในเครื่องมือวิเคราะห์บันทึกการสืบค้นแบบช้าที่ใช้บ่อยมาก คุณสามารถดูข้อความค้นหาที่แย่ที่สุด 10 อันดับแรกตั้งแต่คุณเปิดตัวบันทึกการสืบค้นที่ช้าครั้งล่าสุด นอกจากนี้ยังสามารถบอกจำนวนครั้งที่การสืบค้น BAD เริ่มทำงานและระยะเวลาทั้งหมดที่ใช้บนเซิร์ฟเวอร์


2

บันทึกไว้จริงแต่น่ารำคาญมาก: การแปลงอัตโนมัติสำหรับวันที่ไม่ถูกต้องและการป้อนข้อมูลอื่น ๆ ที่ไม่ถูกต้อง

ก่อน MySQL 5.0.2 MySQL จะให้อภัยค่าข้อมูลที่ผิดกฎหมายหรือไม่เหมาะสมและบังคับให้เป็นค่าทางกฎหมายสำหรับการป้อนข้อมูล ใน MySQL 5.0.2 ขึ้นไปจะยังคงเป็นลักษณะการทำงานเริ่มต้น แต่คุณสามารถเปลี่ยนโหมด SQL ของเซิร์ฟเวอร์เพื่อเลือกการปฏิบัติต่อค่าที่ไม่ดีแบบดั้งเดิมมากขึ้นเพื่อให้เซิร์ฟเวอร์ปฏิเสธและยกเลิกคำสั่งที่เกิดขึ้น

สำหรับวันที่: บางครั้งคุณจะ "โชคดี" เมื่อ MySQL ไม่ปรับอินพุตให้เป็นวันที่ใกล้เคียงที่ถูกต้อง แต่จะเก็บไว้แทน0000-00-00ซึ่งตามคำจำกัดความไม่ถูกต้อง อย่างไรก็ตามถึงอย่างนั้นคุณอาจต้องการให้ MySQL ล้มเหลวแทนที่จะเก็บค่านี้ไว้ให้คุณอย่างเงียบ ๆ



1

โดยค่าเริ่มต้น InnoDB จะจัดเก็บตารางทั้งหมดในพื้นที่ตารางเดียวทั่วโลกซึ่งจะไม่มีวันหดตัวไม่หดตัว

คุณสามารถใช้ได้ innodb_file_per_tableซึ่งจะทำให้แต่ละตารางอยู่ในพื้นที่ตารางแยกกันซึ่งจะถูกลบเมื่อคุณวางตารางหรือฐานข้อมูล

วางแผนล่วงหน้าเนื่องจากคุณต้องถ่ายโอนข้อมูลและกู้คืนฐานข้อมูลเพื่อเรียกคืนพื้นที่ไม่เช่นนั้น

ใช้ Per-Table Tablespaces


1

หากคุณใส่ค่าสตริงว่างของคอลัมน์วันที่และเวลา MySQL จะคงค่าเป็น 00/00/0000 00:00:00 ซึ่งแตกต่างจาก Oracle ซึ่งจะบันทึกค่า null


1

ในระหว่างการวัดประสิทธิภาพของฉันที่มีชุดข้อมูลขนาดใหญ่และช่อง DATETIME การทำแบบสอบถามนี้จะช้ากว่าเสมอ:

SELECT * FROM mytable
WHERE date(date_colum) BETWEEN '2011-01-01' AND ''2011-03-03';

กว่าแนวทางนี้:

SELECT * FROM mytable
WHERE date_column BETWEEN '2011-01-01 00:00:00' AND '2011-03-03 23:59:59'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.