การเชื่อมต่อกับ MySQL จาก PHP นั้นช้ามาก


19

ฉันเพิ่งติดตั้ง XAMPP ครั้งใหม่ เมื่อเปิด PHPMyAdmin ครั้งแรกฉันสังเกตว่ามันช้ามาก มันไม่สมเหตุสมผลที่ localhost ควรใช้เวลาเกือบ 5 วินาทีเพื่อให้ทุกหน้าเปิด ฉันทำกรณีทดสอบขนาดเล็กเพื่อเปลี่ยนตำหนิจาก PHPMyAdmin:

$con = new PDO("mysql:host=localhost;dbname=mysql", "root", "");
$statement = $con->query('SELECT host,user,password FROM user;');
$users = $statement->fetchAll(PDO::FETCH_ASSOC);

สคริปต์ด้านบนใช้เวลาในการรันประมาณ 3 วินาที (แม้ว่าจะใช้เวลาในการโหลดมากกว่า 8 วินาทีในครั้งแรกที่ฉันเรียกใช้)

จากนั้นเพื่อตรวจสอบว่ามันเป็นความผิดของ PDO ที่ฉันพยายามใช้mysql_connectแทน:

$con = mysql_connect("localhost", "root", "");
mysql_select_db("mysql", $con);
$result = mysql_query('SELECT host,user,password FROM user;');

ใช้เวลานานเท่าที่จะเสร็จสิ้น

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

header("Content-Type: text/plain");

for($i = 0; $i < 5000; $i++)
{
    echo sha1(rand()) . "\n";
}

การsha1คำนวณ5,000 ครั้งและหน้าเว็บยังคงปรากฏเป็น Snappier มากกว่าที่ฉันสามารถรีเฟรชหน้าต่างได้

จากนั้นฉันก็พบว่ามันเป็นความผิดของ MySQL แต่อีกครั้งไม่ได้ทำการทดสอบมากนักเพื่อที่จะทราบว่า MySQL นั้นทำงานได้เร็วกว่าที่ฉันต้องการ การใช้ไคลเอนต์ MySQL CLI ผู้ใช้เลือกคิวรี่ไม่ต้องใช้เวลาในการวัด - ทำก่อนที่ฉันจะปล่อยให้คีย์ส่งคืนขึ้นมา

ปัญหาต้องเชื่อมต่อกับ PHP กับ MySQL - เท่าที่ฉันสามารถให้เหตุผลได้ ฉันสามารถค้นหาสิ่งต่าง ๆ เกี่ยวกับ PHP ช้าหรือ MySQL ช้า แต่ไม่มีอะไรเกี่ยวกับ PHP + MySQL ช้ามาก

ขอบคุณทุกคนที่สามารถช่วยฉันแก้ปัญหานี้ได้!


ฉันใช้ XAMPP 1.8.0 สำหรับ win32 ( ลิงก์ดาวน์โหลด )
รุ่น PHP: 5.4.4
รุ่น MySQL: 14.14


แก้ไข: หลังจากเวลามันกลายเป็นฟังก์ชั่นการเชื่อมต่อที่ใช้เวลานานมาก:

$time = microtime(true);

$con = mysql_connect("localhost", "root", "");
mysql_select_db("mysql", $con);

$con_time = microtime(true);

$result = mysql_query('SELECT host,user,password FROM user;');

$sel_time = microtime(true);

printf("Connect time: %f\nQuery time: %f\n",
       $con_time-$time,
       $sel_time-$con_time);

เอาท์พุท:

เชื่อมต่อเวลา: 1.006148
เวลาสอบถาม: 0.000247

อะไรทำให้ PHP ใช้เวลาในการเชื่อมต่อกับฐานข้อมูลมาก? ไคลเอนต์ CLI, HeidiSQL และ MySQL สามารถปรับแต่งการเชื่อมต่อได้ทันที


php -m output โปรด
thinice

คำตอบ:


17

เป็นไปได้ไหมที่ mysql ของคุณพยายามเรียกใช้แบบสอบถาม rev-dns ทุกครั้งที่คุณเชื่อมต่อ? ลองเพิ่มการ my.cnf, mysqld ส่วน: ข้ามชื่อแก้ไข


ทั้ง PHPMyAdmin และไคลเอนต์ MySQL CLI ผิดปกติในตอนนี้ทำให้ฉัน "โฮสต์ '127.0.0.1' ไม่ได้รับอนุญาตให้เชื่อมต่อกับเซิร์ฟเวอร์ MySQL นี้" ด้วยเหตุผลบางอย่างสคริปต์ PHP ยังคงใช้งานได้ แต่ก็ช้าเหมือนก่อน
Hubro

'แอปพลิเคชั่นอ้วน' สำหรับจัดการ mysql - เหมือน mysql workbench - ช้าแค่ไหน?
pQd

การรันเคียวรีเดียวกันจาก MySQL Workbench นั้นเร็วเท่ากับไคลเอนต์ CLI และดังนั้น HeidiSQL
Hubro

เพิ่มเวลาใน php และตรวจสอบว่ามันกำลังเชื่อมต่อหรือเรียกใช้แบบสอบถามที่ใช้เวลานาน
pQd

ขอบคุณสำหรับความคิดเห็นนั้นฉันอัพเดตคำถามของฉัน ทั้งการเชื่อมต่อและการสืบค้นนั้นเร็วสุด ๆ
Hubro

30

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

หากคุณประสบปัญหานี้และใช้ Windows รุ่นหนึ่งก่อน Windows 7 นี่อาจไม่ใช่คำตอบสำหรับปัญหาของคุณ

ทำไมสิ่งนี้จึงเกิดขึ้น

สาเหตุของปัญหานี้คือ IPv4 กับ IPv6

เมื่อคุณใช้ชื่อโฮสต์แทนที่อยู่ IP ไคลเอนต์ MySQL จะเรียกใช้การAAAAค้นหาโฮสต์ (IPv6) เป็นครั้งแรกสำหรับชื่อและลองใช้ที่อยู่นี้ก่อนหากแก้ไขชื่อเป็นที่อยู่ IPv6 ได้สำเร็จ หากขั้นตอนใดล้มเหลว (การจำแนกชื่อหรือการเชื่อมต่อ) มันจะย้อนกลับไปสู่ ​​IPv4 ให้เรียกใช้การAค้นหาและลองใช้โฮสต์นี้แทน

สิ่งนี้หมายความว่าในทางปฏิบัติคือหากการlocalhostค้นหาIPv6 สำเร็จ แต่ MySQL ไม่ได้เชื่อมโยงกับการวนรอบ IPv6 คุณจะต้องรอรอบการหมดเวลาการเชื่อมต่อหนึ่งรอบก่อนที่ IPv4 fallback จะเกิดขึ้นและการเชื่อมต่อจะสำเร็จ

นี่ไม่ใช่ปัญหาก่อนหน้า Windows 7 เพราะการlocalhostแก้ไขทำได้ผ่านไฟล์โฮสต์และมาพร้อมกับการกำหนดค่าล่วงหน้าเท่านั้น127.0.0.1- มันไม่ได้มาพร้อมกับ IPv6 คู่::1กัน

ตั้งแต่ Windows 7 แต่localhostความละเอียดถูกสร้างขึ้นในตัวแก้ไข DNS สำหรับเหตุผลที่ระบุไว้ที่นี่ ซึ่งหมายความว่าการค้นหา IPv6 จะประสบความสำเร็จในขณะนี้ แต่ MySQL ไม่ได้ผูกกับที่อยู่ IPv6 นั้นดังนั้นการเชื่อมต่อจะล้มเหลวและคุณจะเห็นความล่าช้าที่ระบุไว้ในคำถามนี้

นั่นเป็นสิ่งที่ดี แค่บอกวิธีแก้ไขให้เรียบร้อยแล้ว!

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

  • ถ้าคุณย้ายสคริปต์ของคุณไปยังเครื่องที่ว่าคนอื่นเพียงสนับสนุน IPv6, สคริปต์ของคุณจะไม่ทำงาน

  • หากคุณย้ายสคริปต์ของคุณไปยังสภาพแวดล้อมการโฮสต์ที่ใช้ * nix สตริงมายากลlocalhostจะหมายถึงไคลเอนต์ MySQL ต้องการใช้ซ็อกเก็ต Unix หากมีการกำหนดค่าสิ่งนี้จะมีประสิทธิภาพมากกว่าการเชื่อมต่อที่ใช้ลูปแบ็ค IP

พวกเขาฟังดูค่อนข้างสำคัญใช่มั้ย

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

โดยสรุปการใช้ที่อยู่ IP ไม่ใช่ทางออกที่ดีที่สุดแต่น่าจะเป็นที่ยอมรับได้

ดังนั้นทางออกที่ดีที่สุดคืออะไร

วิธีที่ดีที่สุดคือการเปลี่ยนที่อยู่ผูกที่เซิร์ฟเวอร์ MySQL ใช้ อย่างไรก็ตามนี่ไม่ง่ายอย่างที่ใคร ๆ ก็ชอบ ซึ่งแตกต่างจาก Apache, Nginx และแอปพลิเคชันบริการเครือข่ายอื่น ๆ เกือบทั้งหมดที่เคยสร้างขึ้น, MySQL รองรับเฉพาะการเชื่อมโยงแอดเดรสเดียว โชคดีที่ระบบปฏิบัติการรองรับเวทมนต์ที่นี่ดังนั้นเราสามารถทำให้ MySQL สามารถใช้ทั้ง IPv4 และ IPv6 พร้อมกันได้

คุณต้องใช้งาน MySQL 5.5.3 หรือใหม่กว่าและคุณต้องเริ่มต้น MySQL ด้วย--bind-address=อาร์กิวเมนต์บรรทัดคำสั่ง คุณมีเอกสาร 4 ตัวเลือกขึ้นอยู่กับว่าคุณต้องการทำอะไร:

  • คนที่คุณคุ้นเคยและเป็นคนที่คุณน่าจะใช้ (อย่างมีประสิทธิภาพ) 0.0.0.0มากที่สุด สิ่งนี้จะผูกกับที่อยู่ IPv4 ที่มีอยู่ทั้งหมดบนเครื่อง นี้ที่จริงอาจจะไม่ใช่สิ่งที่ดีที่สุดที่จะทำแม้ว่าคุณไม่สนใจเกี่ยวกับ IPv6 ::ในขณะที่มันได้รับความทุกข์ความเสี่ยงเช่นเดียวกับ

  • ที่อยู่ IPv4 หรือ IPv6 อย่างชัดเจน (ตัวอย่างเช่น127.0.0.1หรือ::1สำหรับลูปแบ็ค) นี้ผูกเซิร์ฟเวอร์ไปยังที่อยู่ที่และเพียงว่าที่อยู่

  • ::สตริงมายากล สิ่งนี้จะผูก MySQL กับทุกที่อยู่บนเครื่องทั้งที่อยู่ย้อนกลับและที่อยู่ทางกายภาพของส่วนติดต่อในโหมด IPv4 และ IPv6 นี่อาจเป็นความเสี่ยงด้านความปลอดภัยให้ทำหากคุณต้องการให้ MySQL ยอมรับการเชื่อมต่อจากโฮสต์ระยะไกล

  • ใช้อยู่ IPv6 IPv4 แมป นี่เป็นกลไกพิเศษที่สร้างขึ้นใน IPv6 สำหรับความเข้ากันได้ย้อนหลังในช่วงการเปลี่ยน 4 -> 6 และช่วยให้คุณผูกกับที่อยู่ IPv4 เฉพาะและมันเทียบเท่ากับ IPv6 นี้ค่อนข้างไม่น่าจะเป็นประโยชน์กับคุณสำหรับสิ่งอื่นที่ไม่ใช่ "คู่ย้อนกลับ" ::ffff:127.0.0.1อยู่ นี่น่าจะเป็นทางออกที่ดีที่สุดสำหรับคนส่วนใหญ่ผูกพันเฉพาะกับลูปแบ็ค แต่อนุญาตการเชื่อมต่อทั้ง IPv4 และ IPv6

ฉันจำเป็นต้องแก้ไขไฟล์โฮสต์หรือไม่?

NO อย่าแก้ไขไฟล์โฮสต์ ตัวแก้ไข DNS รู้ว่าต้องทำอะไรโดยlocalhostกำหนดใหม่อย่างดีที่สุดว่าจะไม่มีผลกระทบใด ๆ และที่แย่ที่สุดคือสร้างความสับสนให้กับตัวแก้ไขปัญหา

เกี่ยวกับ--skip-name-resolveอะไร

วิธีนี้อาจแก้ไขปัญหาด้วยเหตุผลที่เกี่ยวข้อง แต่แตกต่างกันเล็กน้อย

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

การปิดใช้งานการจำแนกชื่อจะแก้ไขปัญหานี้ได้ แต่จะมีเครือข่ายอื่น ๆ โดยเฉพาะอย่างยิ่งสิทธิ์การเข้าถึงที่กำหนดค่าให้ใช้ชื่อ DNS ในHostเงื่อนไขจะล้มเหลว

หากคุณกำลังจะทำสิ่งนี้คุณจะต้องกำหนดค่าเงินช่วยเหลือทั้งหมดของคุณให้ใช้ที่อยู่ IP แทนชื่อ


2
ที่สุด! ขอบคุณ! ในที่สุดฉันก็พบคำอธิบายที่เหมาะสมครบถ้วนและชัดเจนเกี่ยวกับสาเหตุทั้งหมดวิธีแก้ปัญหาที่เป็นไปได้และแนวทางปฏิบัติของพวกเขา คุณควรเขียนหนังสือเกี่ยวกับมัน!
tobia.zanarella

4
ผมมีความล่าช้าที่สอง 1 เชื่อมต่อกับ MySQL บน localhost ::1จนกว่าฉันจะเปลี่ยนผูกอยู่เพื่อ น่าเสียดายที่::ffff:127.0.0.1ยังคงให้ฉันล่าช้า 1 วินาที (ไม่ว่าจะใช้skip-name-resolveหรือไม่) ความคิดใด ๆ (บน Windows 8.1)
Simon East

1
@Simon ไม่ใช่เงื่อนงำโดยไม่ต้องมองหา แต่ขั้นตอนแรกในการแก้ไขปัญหาคือพยายามเชื่อมต่อกับทั้ง IPv6 loopback และ IPv4 loopback โดยตรงโดยใช้ที่อยู่ที่ชัดเจนเพื่อตรวจสอบว่า MySQL นั้นกำลังรับฟังและเชื่อมต่อได้จากทั้งสองกอง .
DaveRandom

1
อือ, :: ffff: 127.0.0.1 ไม่ทำงาน ...
Raheel Hasan

ถ้าฉันผูกกับ :: 1, Sqlyog ไม่ทำงาน ... จะทำอย่างไร ??
Raheel Hasan

13

โดยปกติเมื่อเปิดใช้งาน IPv6 ในการเชื่อมต่อเซิร์ฟเวอร์กับ MySQL ที่ใช้localhostจะช้ามาก

การเปลี่ยนที่อยู่เซิร์ฟเวอร์ mysql ในสคริปต์เพื่อ127.0.0.1แก้ไขปัญหา


+1 นี่คือคำตอบที่ถูกต้องสำหรับฉัน ฉันเดาใน Windows 8 พวกเขาย้ายความละเอียดlocalhostไปยังตัวแก้ไข DNS ด้วยเหตุผลที่ @DaveRandom เชื่อมโยงกับ: serverfault.com/questions/4689/…
wwarren

มันใช้งานได้สำหรับฉัน: D
FosAvance

localhostนี้สามารถเกิดขึ้นสำหรับเซิร์ฟเวอร์อื่นที่ไม่ใช่ xx.xxxx.xxxxx.xxxxx.comผมมีปัญหาความล่าช้าเดียวกันสำหรับเซิร์ฟเวอร์ที่อยู่ในแบบฟอร์ม เมื่อฉันเปลี่ยนชื่อเซิร์ฟเวอร์เป็นที่อยู่ IP ของปัญหาก็หายไป
Gruber

1
mysql_connect("localhost", "root", "");

มันค่อนข้างชัดเจนว่าเหตุผลคืออะไร PHP ดีมากในบางสิ่ง แต่ไม่แปลโดยตรงเป็น 'localhost' เป็น '127.0.0.1' คุณต้องลองใช้มันจะลดเวลาในการโหลดหน้าเว็บไซต์โดยรวมของคุณจริงๆเพราะมันช่วยให้ PHP ไม่สามารถตรวจสอบไฟล์โฮสต์ของคุณได้และสิ่งที่ไม่ได้ทำเพื่อรับที่อยู่ IP จริงหลัง 'localhost'


ฉันไม่สามารถหาสิ่งที่คุณพยายามแนะนำปัญหาได้
kasperd

@kasperd การแก้ไข DNS ของ 'localhost'
Xesau

บันทึกจาก '17 - mysql_ * ฟังก์ชั่นเลิกใช้แล้วในขณะนี้และลบออกใน php7
treyBake


0

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

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

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