Kết nối với MySQL từ PHP cực kỳ chậm


19

Tôi vừa mới cài đặt XAMPP. Khi lần đầu mở PHPMyAdmin tôi nhận thấy nó cực kỳ chậm. Điều đó không có nghĩa là trên localhost, phải mất gần 5 giây để mỗi trang mở ra. Tôi đã thực hiện một trường hợp thử nghiệm nhỏ để thay đổi sự đổ lỗi cho 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);

Kịch bản trên chỉ mất khoảng 3 giây để chạy (mặc dù phải mất gần 8 giây để tải lần đầu tiên tôi chạy nó.)

Sau đó, để kiểm tra xem đó có phải là lỗi của PDO không, tôi đã thử sử dụng mysql_connectthay thế:

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

Mất chính xác miễn là kết thúc.

Tôi đã nghĩ rằng đó là lỗi của PHP lúc đầu, nhưng mã PHP và các tệp tĩnh được phục vụ nhanh hơn tôi có thể nhấp vào làm mới. Tôi đã kiểm tra PHP bằng cách chạy tập lệnh nhỏ này:

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

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

5000 sha1tính toán và trang vẫn được hiển thị nhanh hơn tôi có thể làm mới cửa sổ của mình.

Sau đó, tôi nghĩ rằng đó là lỗi của MySQL. Nhưng một lần nữa, tôi đã không mất nhiều thử nghiệm để nhận ra rằng MySQL đang hoạt động nhanh hơn tôi cần. Sử dụng máy khách MySQL CLI, người dùng chọn truy vấn thậm chí không mất thời gian có thể đo được - nó đã được thực hiện trước khi tôi thậm chí còn để phím trả về.

Vấn đề phải là kết nối của PHP với MySQL - đó là điều mà tôi có thể suy luận được. Tôi có thể tìm thấy vô số thứ về PHP chậm hoặc MySQL chậm, nhưng không có gì về PHP + MySQL cực kỳ chậm.

Cảm ơn bất cứ ai có thể giúp tôi giải quyết điều này!


Tôi đang sử dụng XAMPP 1.8.0 cho win32 ( Liên kết tải xuống )
Phiên bản PHP: 5.4.4
Phiên bản MySQL: 14,14


EDIT: Sau thời gian, hóa ra đó là chức năng kết nối mất quá nhiều thời gian:

$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);

Đầu ra:

Thời gian kết nối: 1.006148
Thời gian truy vấn: 0,000247

Điều gì có thể khiến PHP mất nhiều thời gian kết nối với cơ sở dữ liệu? Máy khách CLI, bàn làm việc HeidiSQL và MySQL kết nối ngay lập tức


Xin vui lòng xuất ra php -m
mỏng

Câu trả lời:


17

Có thể là mysql của bạn cố gắng chạy truy vấn rev-dns bất cứ khi nào bạn kết nối? hãy thử thêm vào my.cnf, phần mysqld: bỏ qua tên-giải quyết .


Thật kỳ lạ, cả PHPMyAdmin và máy khách MySQL CLI hiện cung cấp cho tôi "Máy chủ '127.0.0.1' không được phép kết nối với máy chủ MySQL này". Vì một số lý do, tập lệnh PHP vẫn hoạt động, nhưng vẫn chậm như trước
Hubro

các 'ứng dụng béo' để quản lý mysql - như bàn làm việc của mysql - có chậm không?
pQd

Chạy cùng một truy vấn từ MySQL Workbench cũng nhanh như ứng dụng khách CLI và
HeidiQuery

thêm một số thời gian trong php và kiểm tra xem nó đang kết nối hay chạy truy vấn mất nhiều thời gian.
pQd

Cảm ơn cho nhận xét đó, tôi đã cập nhật câu hỏi của tôi. Cả kết nối và truy vấn đều cực nhanh
Hubro

30

Điều này được lấy gần như nguyên văn từ câu trả lời của tôi ở đây , nhưng tôi biết chúng tôi cau mày với câu trả lời chỉ liên kết trên SO nên tôi tưởng tượng các bạn cũng làm như vậy :-)

Nếu bạn đang gặp vấn đề này và sử dụng phiên bản Windows trước Windows 7, đây có lẽ không phải là câu trả lời cho vấn đề của bạn.

Tại sao chuyện này đang xảy ra?

Nguyên nhân của vấn đề này là IPv4 so với IPv6.

Khi bạn sử dụng tên máy chủ thay vì địa chỉ IP, trước tiên máy khách MySQL sẽ chạy AAAAtìm tên máy chủ (IPv6) và thử địa chỉ này trước nếu nó giải quyết thành công tên thành địa chỉ IPv6. Nếu một trong hai bước không thành công (độ phân giải tên hoặc kết nối), nó sẽ chuyển sang IPv4, Athay vào đó hãy chạy tra cứu và thử máy chủ này.

Thực tế điều này có nghĩa là nếu việc localhosttra cứu IPv6 thành công nhưng MySQL không bị ràng buộc với vòng lặp IPv6, bạn sẽ cần đợi một chu kỳ hết thời gian kết nối trước khi dự phòng IPv4 xảy ra và kết nối thành công.

Đây không phải là vấn đề trước Windows 7, vì localhostđộ phân giải được thực hiện thông qua tệp máy chủ và nó chỉ được cấu hình sẵn 127.0.0.1- nó không đi kèm với đối tác IPv6 ::1.

Tuy nhiên, vì Windows 7, localhostđộ phân giải được tích hợp vào bộ giải quyết DNS, vì những lý do được nêu ở đây . Điều này có nghĩa là việc tra cứu IPv6 bây giờ sẽ thành công - nhưng MySQL không bị ràng buộc với địa chỉ IPv6 đó, vì vậy kết nối sẽ thất bại và bạn sẽ thấy độ trễ được nêu trong câu hỏi này.

Thật tuyệt. Chỉ cần cho tôi biết làm thế nào để sửa chữa nó!

Bạn có một vài lựa chọn. Nhìn trên internet, "giải pháp" chung dường như là sử dụng địa chỉ IP một cách rõ ràng thay vì tên, nhưng có một vài lý do để không làm điều này, cả hai đều liên quan đến tính di động, cả hai đều không quan trọng:

  • Nếu bạn di chuyển tập lệnh của mình sang một máy khác chỉ hỗ trợ IPv6, tập lệnh của bạn sẽ không còn hoạt động.

  • Nếu bạn di chuyển tập lệnh của mình sang môi trường lưu trữ dựa trên * nix, chuỗi ma thuật localhostcó nghĩa là máy khách MySQL sẽ thích sử dụng ổ cắm Unix nếu được cấu hình, điều này hiệu quả hơn kết nối dựa trên vòng lặp IP

Họ nghe có vẻ khá quan trọng?

Họ không. Bạn nên thiết kế ứng dụng của mình sao cho loại điều này được xác định trong tệp cấu hình. Nếu bạn di chuyển tập lệnh của mình sang một môi trường khác, rất có thể những thứ khác cũng sẽ cần cấu hình.

Nói tóm lại, bằng cách sử dụng địa chỉ IP không phải là tốt nhất giải pháp, nhưng nó rất có thể là một ai chấp nhận được.

Vậy đâu là giải pháp tốt nhất?

Cách tốt nhất là thay đổi địa chỉ liên kết mà máy chủ MySQL sử dụng. Tuy nhiên, điều này không đơn giản như người ta có thể muốn. Không giống như Apache, Nginx và hầu hết mọi ứng dụng dịch vụ mạng lành mạnh khác từng được tạo ra, MySQL chỉ hỗ trợ một địa chỉ liên kết duy nhất, vì vậy đây không chỉ là trường hợp thêm một địa chỉ khác. May mắn thay, các hệ điều hành hỗ trợ một chút phép thuật ở đây, vì vậy chúng tôi có thể cho phép MySQL sử dụng đồng thời cả IPv4 và IPv6.

Bạn cần chạy MySQL 5.5.3 trở lên và bạn cần khởi động MySQL bằng --bind-address=đối số dòng lệnh. Bạn có 4 tùy chọn tài liệu , tùy thuộc vào những gì bạn muốn làm:

  • Người mà bạn có thể quen thuộc, và người mà bạn có khả năng nhất (sử dụng) một cách hiệu quả , 0.0.0.0. Điều này liên kết với tất cả các địa chỉ IPv4 có sẵn trên máy. Đây thực sự có lẽ không phải là điều tốt nhất để làm ngay cả khi bạn không quan tâm đến IPv6, vì nó chịu rủi ro bảo mật tương tự như ::.

  • Một địa chỉ IPv4 hoặc IPv6 rõ ràng (ví dụ 127.0.0.1hoặc ::1cho loopback). Với phím tắt này, máy chủ đến địa chỉ đó và chỉ địa chỉ đó.

  • Chuỗi ma thuật ::. Điều này sẽ liên kết MySQL với mọi địa chỉ trên máy, cả địa chỉ giao diện vòng lặp và giao diện vật lý, ở chế độ IPv4 và IPv6. Đây có thể là một rủi ro bảo mật, chỉ làm điều này nếu bạn cần MySQL chấp nhận kết nối từ các máy chủ từ xa.

  • Sử dụng địa chỉ IPv6 được ánh xạ IPv4 . Đây là một cơ chế đặc biệt được tích hợp trong IPv6 để tương thích ngược trong quá trình chuyển đổi 4 -> 6 và nó cho phép bạn liên kết với một địa chỉ IPv4 cụ thể và tương đương IPv6. Điều này khá khó có thể hữu ích cho bạn cho bất cứ điều gì ngoài địa chỉ "loopback kép" ::ffff:127.0.0.1. Đây rất có thể là giải pháp tốt nhất cho hầu hết mọi người, chỉ ràng buộc với loopback nhưng cho phép cả kết nối IPv4 và IPv6.

Tôi có cần sửa đổi tập tin máy chủ không?

NO . Đừng sửa đổi tập tin máy chủ. Trình phân giải DNS biết phải làm gì với localhost, xác định lại nó sẽ không có hiệu lực và tệ nhất là nhầm lẫn giữa địa ngục với trình phân giải.

Thế còn --skip-name-resolve?

Điều này cũng có thể khắc phục vấn đề, vì một lý do liên quan nhưng hơi khác nhau.

Nếu không có tùy chọn cấu hình này, MySQL sẽ cố gắng giải quyết tất cả các địa chỉ IP kết nối máy khách thành tên máy chủ thông qua PTRtruy vấn DNS. Nếu máy chủ MySQL của bạn đã được kích hoạt để sử dụng IPv6 nhưng các kết nối vẫn mất nhiều thời gian, có thể là do PTRbản ghi DNS ( ) ngược không được định cấu hình chính xác.

Vô hiệu hóa độ phân giải tên sẽ khắc phục vấn đề này, nhưng nó có các phân nhánh khác, đáng chú ý là mọi quyền truy cập được định cấu hình để sử dụng tên DNS trong Hostđiều kiện sẽ không thành công.

Nếu bạn định làm điều này, bạn sẽ cần phải định cấu hình tất cả các khoản tài trợ của mình để sử dụng địa chỉ IP thay vì tên.


2
Cuối cùng! Cảm ơn cảm ơn! Cuối cùng tôi đã tìm thấy một lời giải thích phù hợp, đầy đủ và rõ ràng về tất cả các nguyên nhân, giải pháp có thể và các phản ứng của chúng. Bạn nên viết một cuốn sách về nó!
tobia.zanarella

4
Tôi đã bị chậm 1 giây khi kết nối với MySQL trên localhost cho đến khi tôi thay đổi địa chỉ liên kết thành ::1. Thật không may ::ffff:127.0.0.1tiếp tục cho tôi một sự chậm trễ 1 giây (bất kể sử dụng skip-name-resolvehay không), bất kỳ ý tưởng tại sao? (trên Windows 8.1)
Simon East

1
@Simon Không phải là đầu mối mà không tìm kiếm, nhưng bước đầu tiên để gỡ lỗi sẽ là thử kết nối trực tiếp với cả loopback IPv6 và loopback IPv4 bằng cách sử dụng các địa chỉ rõ ràng để xác minh rằng MySQL thực sự đang nghe và có thể kết nối trên cả hai ngăn xếp và gỡ lỗi từ đó .
DaveRandom

1
phải, :: ffff: 127.0.0.1 không hoạt động ...
Raheel Hasan

Nếu tôi liên kết nó với :: 1, Sqlyog không hoạt động ... phải làm gì ??
Raheel Hasan

13

Thông thường khi IPv6 được kích hoạt trong các kết nối máy chủ tới MySQL sử dụng localhostthì cực kỳ chậm.

Thay đổi địa chỉ máy chủ mysql trong tập lệnh để 127.0.0.1giải quyết vấn đề.


+1 đây là câu trả lời đúng cho tôi. Tôi đoán trong Windows 8, họ đã chuyển độ phân giải sang trình phân giải localhostDNS với lý do @DaveRandom liên kết đến: serverfault.com/questions/4689/
trộm

Nó hoạt động với tôi: D
FosAvance

Điều này có thể xảy ra cho các máy chủ khác hơn localhost. Tôi đã có cùng một vấn đề chậm trễ cho một địa chỉ máy chủ trong mẫu xx.xxxx.xxxxx.xxxxx.com. Khi tôi thay đổi tên máy chủ thành địa chỉ IP của nó, vấn đề đã biến mất.
Gruber

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

Chà, rõ ràng lý do là gì. PHP thực sự giỏi một số thứ, nhưng không dịch trực tiếp 'localhost' thành '127.0.0.1'. Bạn phải thử điều đó, nó thực sự sẽ làm giảm thời gian tải trang web tổng thể của bạn, bởi vì nó ngăn PHP kiểm tra tệp HOSTS của bạn và những gì không làm để có được địa chỉ IP thực phía sau 'localhost'


Tôi không thể tìm ra những gì bạn đang cố gắng đề xuất vấn đề là.
kasperd

@kasperd DNS phân giải 'localhost'
Xesau

lưu ý từ '17 - các hàm mysql_ * hiện không được chấp nhận và bị xóa trong php7
treyBake


0

Bạn cũng có thể loại bỏ sự chậm lại truy vấn bằng cách thực hiện một điều chỉnh nhỏ cho biến kết nối db của bạn (hy vọng trong một tệp riêng biệt từ các tập lệnh của bạn để có tính di động). Thay đổi giá trị máy chủ thành "127.0.0.1" thay vì "localhost". Điều này bỏ qua việc tra cứu DNS dài cho localhost.

Hi vọng điêu nay co ich!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.