Hiển thị các bài đăng có nhãn PHP. Hiển thị tất cả bài đăng
Hiển thị các bài đăng có nhãn PHP. Hiển thị tất cả bài đăng
Thứ Hai, 17 tháng 8, 2020
How to remove the character ?
What is the character ?
is a kind of “end of line” character – Unicode Character ‘ZERO WIDTH NO-BREAK SPACE’ (U+FEFF). \
Normally there are 3 common “strange” characters: EF, BB, BF.
How to remove the character ?
There are multiple ways to fix the issue. for example: write a java script function to replace the strange character to a empty string.
But, we think the most efficient way is using the free tool NotePad++ to convert the original file to UTF-8 (without BOM) format.
Menu Encoding –> Convert to UTF-8.
After you did the converting, the strange space on web page will gone.
http://www.gogototo.com/resolve-the-strange-character-65279-in-wordpress-web-page.html
Thứ Bảy, 8 tháng 6, 2019
Tăng tốc MySQL
MySQL là 1 Database kết hợp chặt chẽ với PHP trong rất nhiều ứng dụng web động. Nhờ tính năng mã nguồn mở và nhỏ gọn , MySQL hiện đang là hệ Database nhanh nhất cho các ứng dụng thông thường. Tuy nhiên theo thời gian , các ứng dụng web sử dụng MySQL ngày càng "phình" to ra và Website của bạn ngày càng chạy chậm đi. Đó có phải là điều không thể tránh khỏi ? Hãy tham khảo bài viết sau đây để tăng tốc MySQL và website của bạn lên gấp nhiều lần.
Một ngày kia bạn nhận ra rằng website của bạn chạy chậm đi, có thể là do đường truyền nhưng còn 1 nguyên nhân khác, đó là máy chủ server tính toán quá nhiều dẫn đến kết quả đưa ra chậm (Xem phần phụ lục để biết cách xác định nguyên nhân gây chậm). Đây là điều thường thấy ở những website về Diễn Đàn (Forum) , Tin Tức (Portal) và Thương mại điện tử (Ecommerce). Khi số lượng thành viên , số lượng bài viết tăng lên , đồng nghĩa với việc Database khi truy vấn (query) 1 yêu cầu phải duyệt qua tất cả các dữ liệu hiện có để tìm ra dữ liệu thích hợp. Cũng giống như 1 quyển sách. Nếu sách là mỏng , bạn dễ dàng tìm ra thông tin mình cần. Nhưng khi sách dầy lên , thời gian tìm kiếm của bạn sẽ tăng đáng kể.
Việc Database quá tải còn dẫn đến nhiều thiệt hại khác, các hàng đợi(Queuie) dài ra , file logs lớn lên chiếm hết không gian đĩa và user khi kết nối sẽ bị từ chối. Rõ ràng là câu báo lỗi "Too many connections" không phải là hiếm gặp trong các website trên Internet. Những lỗi trên thông thường bắt nguồn từ khâu định nghĩa Database (define) hay không sử dụng "Mục Lục" (Indexes). Khắc phục những thiếu sót trên , Database của bạn sẽ "nhẹ nhàng" và nhanh chóng đáng kể. Hãy xem xét ví dụ sau:
CODE
CREATE TABLE employee (
employee_number char(10) NOT NULL,
firstname varchar(40),
surname varchar(40),
address text,
tel_no varchar(25),
salary int(11),
overtime_rate int(10) NOT NULL
); Và để tìm thông tin Lương của Nguyễn Nam (mã số 101802) , bạn sẽ query như sau:
CODE
SELECT salary FROM employee WHERE employee_number = '101832';MySQL biết rằng phải tìm ở table Employee nhưng nó sẽ không biết bắt đầu từ đâu. Thậm chí nó cũng không biết trước rằng có bao nhiêu kết quả . Do đó nó sẽ duyệt qua tất cả danh sách (vd Hơn 300000 người) để tìm thông tin về Nguyễn Nam.
"Mục Lục" (Index) là 1 file riêng biệt được lưu trữ ở máy chủ và chỉ chứa những Fields mà bạn muốn nó chứa. Nếu bạn tạo 1 Index cho Field employee_number char (mã số công nhân) , MySQL sẽ dễ dàng tìm ra được mã số 1 cách nhanh chóng. Trở lại ví dụ quyển sách , khi cần tìm 1 thông tin , ta thường lật ngay tới phần "Mục Lục" và tìm từ đó để tăng tốc độ tìm. Và việc tạo ra Index này sẽ làm bạn thấy Database của bạn chạy nhanh 1 cách khác thường.
Nhưng trước khi sửa lại cấu trúc của table ở trên , tôi sẽ hướng dẫn bạn 1 chút về cách theo dõi kết quả "Tăng tốc MySQL" mà bạn đang làm. Hãy sử dụng lệnh EXPLAIN
Cú pháp:
CODE
EXPLAIN Query;Bằng lệnh này bạn sẽ nhận ra được với câu Query của bạn , điều gì đang xảy ra và kiểu kết hợp (Join) nào đang diễn ra bên trong.
Xem ví dụ sau:
CODE
MySQL>EXPLAIN SELECT employee_number,firstname,surname FROM employee WHERE employee_number= '10875';
+----------+------+---------------+------+---------+------+------+------------+
| table | type | possible_keys | key | key_len | ref | rows | Extra |
+----------+------+---------------+------+---------+------+------+------------+
| employee | ALL | NULL | NULL | NULL | NULL | 9475 | where used |
+----------+------+---------------+------+---------+------+------+------------+Giải thích:
- table : Table nào đang liên quan đến output data
- type : Đây là thông tin quan trọng , nó cho chúng ta biết kiểu query nào nó đang sử dụng. Mức độ từ tốt nhất đến chậm nhất như sau: system, const, eq_ref, ref, range, index, all
- possible_keys : Đưa ra những Index có thể sử dụng để query
- key : và Index nào đang được sử dụng
- key_len : Chiều dài của từng mục trong Index
- ref : Cột nào đang sử dụng
- rows : Số hàng (rows) mà MySQL dự đoán phải tìm
- extra : Thông tin phụ , thật tệ nếu tại cột này là "using temporary" hay "using filesort"
Wow , nhìn lại câu query của chúng ta mới thật khủng khiếp. Không có Possible_keys nào được sử dụng, MySQL phải duyệt qua 9475 hàng mới tìm ra cái ta cần (Hãy tưởng tượng 1 Forum sẽ có đến hơn 200 000 hàng).
Bây giờ chúng ta sẽ thêm Index vào và query lại
CODE
MySQL>ALTER TABLE employee ADD INDEX(employee_number char);
MySQL>EXPLAIN SELECT employee_number,firstname,surname FROM employee WHERE employee_number= '10875';
+----------+-------+---------------+---------+---------+-------+------+-------+
| table | type | possible_keys | key | key_len | ref | rows | Extra |
+----------+-------+---------------+---------+---------+-------+------+-------+
| employee | const | PRIMARY | PRIMARY | 10 | const | 1 | |
+----------+-------+---------------+---------+---------+-------+------+-------+Tốt hơn nhiều rồi , kiểu TYPE = Const có nghĩa rằng MySQL hiểu ra chỉ có 1 hàng đúng với ý ta, và thể hiện qua cột Rows = 1 , kiểu key= PRIMARY được sử dụng và chiều dài key_len là 10.Chỉ tìm 1 hàng tất nhiên rằng tốt hơn nhiều so với tìm 9475 hàng
Vậy câu hỏi đặt ra là , nếu tôi muốn thêm Index cho những cột mà có thể có nhiều hơn 1 kết quả khi query thì sao?
Vẫn add index như bình thường ,giả sử bạn cần tìm những người có họ là Nguyễn , tên là Nam
CODE
MySQL>ALTER TABLE employee ADD INDEX(surname,firstname);
MySQL>EXPLAIN SELECT overtime_rate FROM employee WHERE surname='Nguyễn' and firstname="Nam";
+--------+------+-------------------+---------+---------+-------+------+-----------+
| table | type | possible_keys | key | key_len | ref | rows | Extra |
+--------+------+-------------------+---------+---------+-------+------+-----------+
|employee| ref | surname,surname_2 | surname | 41 | const | 1 |where used |
+--------+------+-------------------+---------+---------+-------+------+-----------+Tuy nhiên , nếu chỉ cần Firstname
CODE
MySQL>EXPLAIN SELECT overtime_rate FROM employee WHERE firstname='Name';
+----------+------+---------------+------+---------+------+------+------------+
| table | type | possible_keys | key | key_len | ref | rows | Extra |
+----------+------+---------------+------+---------+------+------+------------+
| employee | ALL | NULL | NULL | NULL | NULL | 9475| where used |
+----------+------+---------------+------+---------+------+------+------------+thì MySQL sẽ tìm hết vì không hề có Index cho Firstname mà chỉ có Index cho (Surname,Firstname)
Khi nào thì cần Add Index ? Bất cứ khi nào bạn thay đổi Table bạn đều cần Add Index lại , giống như khi bạn thay đổi nội dung quyển sách , bạn cần phải làm lại mục lục. Vậy hãy cân nhắc , nếu Database của bạn sử dụng INSERT hay UPDATE nhiều hơn là SELECT thì Index chỉ làm chậm thêm mà thôi.
Có thể nhanh hơn nữa không ? Có ! Bạn không cần phải làm Index cho cả Field mà chỉ cần 1 phần. Giống như chi tiết Mục Lục của sách mà quá dài cũng làm bạn khá vất vả, do đó họ chỉ trích dẫn 1 tựa đề. Quay lại với table của chúng ta , Surname và Firstname chỉ maximum là 40 chars , nếu chúng ta index nó , chúng ta tạo ra mỗi record đến 80 chars . Có thể tiết kiệm bằng cách sau
CODE
MySQL>ALTER TABLE employee ADD INDEX(surname(20),firstname(20));
Bây giờ thì bạn tiết kiệm được đến 50% mà vẫn đảm bảo được tốc độ rồi đó (trừ phi bạn làm Index quá ngắn). Có thể bạn nói đĩa cứng server tôi "vô tư" nhưng hãy nhớ rằng "Nhỏ hơn là nhanh hơn".
ĐIỀU KÌ DIỆU VỚI OPTIMIZE VÀ ANALYZE
"Ma thuật" của MySQL là biết cách chọn khoá (key) nào để query(nếu có). Quá trình này gọi là "query optimizer", nó sẽ "liếc" qua những Index đang có để quyết định sẽ dùng Index nào để tìm. Hãy tưởng tượng bạn đang tìm 1 dĩa CD của "Maria Carrey" có tên là "I Love You" , có nghĩa là có 2 Indexes ở đây , 1 cho tên tác giả và 1 cho tên CD. Bạn nhận thấy rằng danh mục có 20000 tên tác giả và 400000 tên Album. Một cách đơn giản ,bạn sẽ tìm theo tên tác giả. Khi có được , bạn lại thấy rằng "Maria Carrey" có 50 CDs và CD "I Love You" bắt đầu bằng chữ I. Đơn giản và dễ dàng tìm ra cái mình muốn phải không ? MySQL cũng vậy nhưng ...bạn phải chỉ cho nó bằng cách:
CODE
ANALYZE TABLE tablename;
Những lệnh DELETE và UPDATE để lại rất nhiều những khoảng trống (gaps) vô nghĩa cho table(Đặc biệt là khi bạn dùng kiểu varchar hay text/blob). Điều đó có nghĩa rằng MySQL cũng phải đọc và phân tích những thứ vô nghĩa đó khi query. Điều này được khắc phục khi bạn chạy
CODE
OPTIMIZE tablename;
Do đó 2 câu lệnh trên bạn nên chạy 1 cách thường xuyên để bảo đảm tối ưu hoá Database của mình.
Sưu tầm http://www.thienduongweb.com/home/post-tang-toc-mysql-234.html
Tối ưu hóa truy vấn MySQL cho site có lượng truy cập lớn
Mình xin bắt đầu với 1 database có bảng users với khoảng 1 triệu
records, nó là kinh nghiệm mình gặt hái được trong quá trình tham gia
phát triển dự án game online UGH!
Thân chào các bạn Lập Trình Web!
Trong sự nghiệp lập trình web của mình, hẳn không ít coder chúng ta không có những mục tiêu, hoài bão là xây dựng, thực hiện được những dự án lớn, có tầm cỡ quốc gia, quốc tế. Chẳng hạn Vật Giá, Chợ Điện Tử, Zing, Zooz... ở Việt Nam, hay lớn hơn là những YouTube, MySpace, Facebook... trên qui mô toàn cầu.
Khi nói đến những dự án lớn thì một trong những vấn đề được các coder quan tâm hàng đầu đó là hiệu suất của dự án. Một site nhỏ với qui mô vài trăm user, dung lượng database chưa đáng kể thì thời gian truy vấn, tải trang chưa phải là vấn đề bạn cần quan tâm. Nhưng theo thời gian site phát triển với tốc độ chóng mặt, chẳng mấy chốc đã có tới hàng triệu users tham gia, tỉ lệ thuận với nó là bảng users có hàng triệu records, database phình to, dung lượng có thể lên đến hàng gigabyte, hàng chục gigabyte thậm chí hàng trăm gigabyte... Lúc này, ngoài việc triển khai các kế hoạch kinh doanh, khai thác lợi nhuận (có thể để bộ phận kinh doanh lo) thì một vấn đề lớn đặt ra cho các coder chúng ta là làm sao để website với 1 database to như vậy vẫn chạy mượt mà như là database nhỏ!? Ngoài những vấn đề về đầu tư cơ sở hạ tầng khủng với server cấu hình cao, database server riêng rẽ, chuẩn hóa code ra mình mạo muội viết bài viết này để chúng ta cùng chia sẽ những kinh nghiệm, thủ thuật về tối ưu truy vấn MySQL với một database lớn.
Mình xin bắt đầu với 1 database có bảng users với khoảng 1 triệu records, nó là kinh nghiệm mình gặt hái được trong quá trình tham gia phát triển dự án game online UGH!
* Thủ thuật 1: INSERT
- Ngữ cảnh: chúng ta có 2 bảng users (1 triệu records), messages (empty) với cấu trúc:
users
- user_id
- name
- money
messages
- message_id
- user_id
- subject
- body
- Yêu cầu: một ngày đẹp trời, bạn muốn gửi thông điệp đến tất cả các users có số money ít hơn 1 USD rằng: Tai khoan cua ban sap het! Hay nop them tien vao tai khoan.
- Cách làm thông thường:
PHP Code:
=> Cách làm tối ưu: dùng 1 query để giải quyết tình huống này
PHP Code:
Kết quả: thời gian xử lí giảm xuống gần 20 lần
Thủ thuật trong trường hợp này:
- Kết hợp INSERT và SELECT để thay thế cho while của PHP.
- Dùng CONCAT để lấy name của user.
* Thủ thuật 2: UPDATE
- Ngữ cảnh: có 2 bảng users (1 triệu records), user_scores (2 triệu records)
users
- user_id
- name
- total_scores
- max_scores_can_contain
user_scores
- user_score_id
- user_id
- score_type_id
- scores
- Yêu cầu: một user sẽ được cộng thêm 1 số điểm là scores trong bảng user_scores tương ứng với mỗi score_type_id (ưu tiên theo score_type_id) mà user đang có. Nhưng tổng số scores hiện có và scores của các score_type_id này không được vượt quá con số max_scores_can_contain trong bảng users, nếu vượt quá thì chỉ lấy số scores tương ứng với tổng số scores bằng max_scores_can_contain. Sao yêu cầu loằng ngoằng vậy ta ? Chắc do nó là advanced nên mới thế .
- Giải quyết vấn đề:
PHP Code:
=> Tối ưu:
PHP Code:
Kết quả: thời gian xử lí giảm đi gần 10 lần
Thủ thuật:
- Dùng WHEN ELSE chia case và cộng ngay trong câu truy vấn.
Ok, đây là 2 tut đầu của mình với cơ sở hạ tầng đơn giản chỉ là Xampp server được cài đặt trên laptop của mình. Có lẽ 1 phần vì cấu hình server không được gút cho lắm nên có đoạn script chạy hơi bị lâu. Không sao, điều quan trọng là chúng ta so sánh được thời gian trước và sau khi tối ưu. Còn trên thực tế với database này thì chắc là bạn đã phải sắm database server từ lâu rồi !
Mình cũng đính kèm theo source của 2 tut này http://www.mediafire.com/?lhbcwmodm9q8czo, các bạn có thể thao tác:
- Giải nén, copy thư mục này lên server, ví dụ tên thư mục là MySQL_optimize
- Tạo database MySQL_optimize
- Import file MySQL_optimize.sql vào database này
- Chỉnh lại thông số trong file config.php
- Test tutorial nào thì bỏ comment out tương ứng của tutorial đó trong file index.php, đoạn include tutorial_1.php, tutorial_2.php
- Trong file tutorial:
+ Bỏ comment out trong step 1, chạy file index.php để có sample data
+ Bỏ comment out trong step 2, chạy file index.php để có kết quả lúc chưa tối ưu
+ Bỏ comment out trong step 3, chạy file index.php để có kết quả lúc đã tối ưu
Test, so sánh và thưởng thức thành quả !
Trong sự nghiệp lập trình web của mình, hẳn không ít coder chúng ta không có những mục tiêu, hoài bão là xây dựng, thực hiện được những dự án lớn, có tầm cỡ quốc gia, quốc tế. Chẳng hạn Vật Giá, Chợ Điện Tử, Zing, Zooz... ở Việt Nam, hay lớn hơn là những YouTube, MySpace, Facebook... trên qui mô toàn cầu.
Khi nói đến những dự án lớn thì một trong những vấn đề được các coder quan tâm hàng đầu đó là hiệu suất của dự án. Một site nhỏ với qui mô vài trăm user, dung lượng database chưa đáng kể thì thời gian truy vấn, tải trang chưa phải là vấn đề bạn cần quan tâm. Nhưng theo thời gian site phát triển với tốc độ chóng mặt, chẳng mấy chốc đã có tới hàng triệu users tham gia, tỉ lệ thuận với nó là bảng users có hàng triệu records, database phình to, dung lượng có thể lên đến hàng gigabyte, hàng chục gigabyte thậm chí hàng trăm gigabyte... Lúc này, ngoài việc triển khai các kế hoạch kinh doanh, khai thác lợi nhuận (có thể để bộ phận kinh doanh lo) thì một vấn đề lớn đặt ra cho các coder chúng ta là làm sao để website với 1 database to như vậy vẫn chạy mượt mà như là database nhỏ!? Ngoài những vấn đề về đầu tư cơ sở hạ tầng khủng với server cấu hình cao, database server riêng rẽ, chuẩn hóa code ra mình mạo muội viết bài viết này để chúng ta cùng chia sẽ những kinh nghiệm, thủ thuật về tối ưu truy vấn MySQL với một database lớn.
Mình xin bắt đầu với 1 database có bảng users với khoảng 1 triệu records, nó là kinh nghiệm mình gặt hái được trong quá trình tham gia phát triển dự án game online UGH!
* Thủ thuật 1: INSERT
- Ngữ cảnh: chúng ta có 2 bảng users (1 triệu records), messages (empty) với cấu trúc:
users
- user_id
- name
- money
messages
- message_id
- user_id
- subject
- body
- Yêu cầu: một ngày đẹp trời, bạn muốn gửi thông điệp đến tất cả các users có số money ít hơn 1 USD rằng: Tai khoan cua ban sap het! Hay nop them tien vao tai khoan.
- Cách làm thông thường:
PHP Code:
CODE
$query = MySQL_query("SELECT * FROM users WHERE money < 1");
$subject = "Money cua ban sap het!";
while ( $row = db_fetch_object($query) ) {
$body = $row->name ." than men! So money trong tai
khoan cua ban chi con chua den 1 USD - mua duoc 1 kg rau muong luoc.
Hay nop them tien vao tai khoan de giao dich khong bi gian doan.";
MySQL_query("INSERT INTO messages (user_id, subject, body) VALUES ($row->user_id, '$subject', '$body')");
}
// Processed in 67.0436019897 sec => Cách làm tối ưu: dùng 1 query để giải quyết tình huống này
PHP Code:
CODE
MySQL_query("
INSERT INTO messages
(user_id, subject, body)
SELECT
user_id, 'Money cua ban sap het!', CONCAT(name, ' than men!
So money trong tai khoan cua ban chi con chua den 1 USD - mua duoc 1 kg
rau muong luoc. Hay nop them tien vao tai khoan de giao dich khong bi
gian doan.')
FROM users
WHERE money < 1
");
// Processed in: 3.5900 sec Kết quả: thời gian xử lí giảm xuống gần 20 lần
Thủ thuật trong trường hợp này:
- Kết hợp INSERT và SELECT để thay thế cho while của PHP.
- Dùng CONCAT để lấy name của user.
* Thủ thuật 2: UPDATE
- Ngữ cảnh: có 2 bảng users (1 triệu records), user_scores (2 triệu records)
users
- user_id
- name
- total_scores
- max_scores_can_contain
user_scores
- user_score_id
- user_id
- score_type_id
- scores
- Yêu cầu: một user sẽ được cộng thêm 1 số điểm là scores trong bảng user_scores tương ứng với mỗi score_type_id (ưu tiên theo score_type_id) mà user đang có. Nhưng tổng số scores hiện có và scores của các score_type_id này không được vượt quá con số max_scores_can_contain trong bảng users, nếu vượt quá thì chỉ lấy số scores tương ứng với tổng số scores bằng max_scores_can_contain. Sao yêu cầu loằng ngoằng vậy ta ? Chắc do nó là advanced nên mới thế .
- Giải quyết vấn đề:
PHP Code:
CODE
// Query tat ca users, chi update nhung user co scores > 0
$query = MySQL_query("SELECT * FROM user_scores WHERE scores > 0");
while ( $row = MySQL_fetch_object($query) ) {
// Lay object cua user nay
$user = MySQL_fetch_object(MySQL_query("SELECT * FROM users WHERE user_id = $row->user_id"));
// Chi cong nhung user cos total_scores < max_scores_can_contain
if ( $user->total_scores < $user->max_scores_can_contain ) {
// Bat dau kiem tra bien scores_addition se cong vao
if ( $user->total_scores + $row->scores >= $user->max_scores_can_contain ) {
// Chi cong vao de total scores = max scores can contain
$scores_addition = $user->max_scores_can_contain - $user->total_scores;
} else {
// Cong binh thuong
$scores_addition = $row->scores;
}
// Bat dau cong
MySQL_query("UPDATE users SET total_scores = total_scores + $scores_addition WHERE user_id = $user->user_id");
}
}
// Processed in 530.916620016 sec => Tối ưu:
PHP Code:
CODE
MySQL_query("
UPDATE users AS u
LEFT JOIN user_scores AS us
ON u.user_id = us.user_id
SET u.total_scores = u.total_scores +
(
CASE
WHEN (u.total_scores + us.scores) > u.max_scores_can_contain
THEN (u.max_scores_can_contain - u.total_scores)
ELSE us.scores
END
)
WHERE u.total_scores < u.max_scores_can_contain
AND us.scores > 0
");
// Processed in 59.2287611961 sec Kết quả: thời gian xử lí giảm đi gần 10 lần
Thủ thuật:
- Dùng WHEN ELSE chia case và cộng ngay trong câu truy vấn.
Ok, đây là 2 tut đầu của mình với cơ sở hạ tầng đơn giản chỉ là Xampp server được cài đặt trên laptop của mình. Có lẽ 1 phần vì cấu hình server không được gút cho lắm nên có đoạn script chạy hơi bị lâu. Không sao, điều quan trọng là chúng ta so sánh được thời gian trước và sau khi tối ưu. Còn trên thực tế với database này thì chắc là bạn đã phải sắm database server từ lâu rồi !
Mình cũng đính kèm theo source của 2 tut này http://www.mediafire.com/?lhbcwmodm9q8czo, các bạn có thể thao tác:
- Giải nén, copy thư mục này lên server, ví dụ tên thư mục là MySQL_optimize
- Tạo database MySQL_optimize
- Import file MySQL_optimize.sql vào database này
- Chỉnh lại thông số trong file config.php
- Test tutorial nào thì bỏ comment out tương ứng của tutorial đó trong file index.php, đoạn include tutorial_1.php, tutorial_2.php
- Trong file tutorial:
+ Bỏ comment out trong step 1, chạy file index.php để có sample data
+ Bỏ comment out trong step 2, chạy file index.php để có kết quả lúc chưa tối ưu
+ Bỏ comment out trong step 3, chạy file index.php để có kết quả lúc đã tối ưu
Test, so sánh và thưởng thức thành quả !
How to Optimize MySQL Queries for Speed and Performance
You can deploy fast, secure, and trusted MySQL database instances on Alibaba Cloud. Alibaba has an advanced network of cloud-based technologies and their breaking performance and flexible billing have enabled cloud without borders for its over one million paid customers.
Alibaba Cloud has continued to show enormous contribution to the open-source communities and has empowered developers worldwide. Alibaba Cloud was the winner of the prestigious 2018 MySQL Corporate Contributor Award and is also a platinum sponsor of the MariaDB foundation.
In this guide, we will take you through the steps of optimizing SQL queries and databases on your Alibaba Cloud Elastic Compute Service (ECS) instance. This will guarantee stability, scalability, reliability and speed of applications and websites running on your Alibaba Cloud instance.
Prerequisites
A valid Alibaba cloud account. If you don't have one already, you can sign up for an Alibaba Cloud and enjoy $300 worth in Free Trial.
A server running your favorite operating system that can support MySQL (e.g. Ubuntu, Centos, Debian).
MySQL database server.
A MySQL user capable of running root commands.
Tip #1: Index All Columns Used in 'where', 'order by', and 'group by' Clauses
Apart from guaranteeing uniquely identifiable records, an index allows MySQL server to fetch results faster from a database. An index is also very useful when it comes to sorting records.
MySQL indexes may take up more space and decrease performance on inserts, deletes, and updates. However, if your table has more than 10 rows, they can considerably reduce select query execution time.
It is always advisable to test MySQL queries with a "worst case scenario" sample amount of data to get a clearer picture of how the query will behave on production.
Consider a case where you are running the following SQL query from a database with 500 rows without an index:
mysql> select customer_id, customer_name from customers where customer_id='140385';
The above query will force MySQL server to conduct a full table scan (start to finish) to retrieve the record that we are searching.
Luckily, MySQL has a special 'EXPLAIN' statement that you can use alongside select, delete, insert, replace and update statements to analyze your queries.
Once you append the query before an SQL statement, MySQL displays information from the optimizer about the intended execution plan.
If we run the above SQL one more time with the explain statement, we will get a full picture of what MySQL will do to execute the query:
mysql> explain select customer_id, customer_name from customers where customer_id='140385';
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | customers | NULL | ALL | NULL | NULL | NULL | NULL | 500 | 10.00 | Using where |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
As you can see, the optimizer has displayed very important information that can help us to fine-tune our database table. First, it is clear that MySQL will conduct a full table scan because key column is 'NULL'. Second, MySQL server has clearly indicated that it's going to conduct a full scan on the 500 rows in our database.
To optimize the above query, we can just add an index to the 'customer_id' field using the below syntax:
mysql> Create index customer_id ON customers (customer_Id);
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
If we run the explain statement one more time, we will get the below results:
mysql> Explain select customer_id, customer_name from customers where customer_id='140385';
+----+-------------+-----------+------------+------+---------------+-------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+------+---------------+-------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | customers | NULL | ref | customer_id | customer_id | 13 | const | 1 | 100.00 | NULL |
+----+-------------+-----------+------------+------+---------------+-------------+---------+-------+------+----------+-------+
From the above explain output, it's clear that MySQL server will use our index (customer_Id) to search the table. You can clearly see that the number of rows to scan will be 1. Although I run the above query in a table with 500 records, indexes can be very useful when you are querying a large dataset (e.g. a table with 1 million rows).
Tip 2: Optimize Like Statements With Union Clause
Sometimes, you may want to run queries using the comparison operator 'or' on different fields or columns in a particular table. When the 'or' keyword is used too much in where clause, it might make the MySQL optimizer to incorrectly choose a full table scan to retrieve a record.
A union clause can make the query run faster especially if you have an index that can optimize one side of the query and a different index to optimize the other side.
Example, consider a case where you are running the below query with the 'first_name' and 'last_name' indexed:
mysql> select * from students where first_name like 'Ade%' or last_name like 'Ade%' ;
The query above can run far much slower compared to the below query which uses a union operator merge the results of 2 separate fast queries that takes advantage of the indexes.
mysql> select from students where first_name like 'Ade%' union all select from students where last_name like 'Ade%' ;
Tip 3: Avoid Like Expressions With Leading Wildcards
MySQL is not able to utilize indexes when there is a leading wildcard in a query. If we take our example above on the students table, a search like this will cause MySQL to perform full table scan even if you have indexed the 'first_name' field on the students table.
mysql> select * from students where first_name like '%Ade' ;
We can prove this using the explain keyword:
mysql> explain select * from students where first_name like '%Ade' ;
+----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | students | NULL | ALL | NULL | NULL | NULL | NULL | 500 | 11.11 | Using where |
+----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
As you can see above, MySQL is going to scan all the 500 rows in our students table and make will make the query extremely slow.
Tip 4: Take Advantage of MySQL Full-Text Searches
If you are faced with a situation where you need to search data using wildcards and you don't want your database to underperform, you should consider using MySQL full-text search (FTS) because it is far much faster than queries using wildcard characters.
Furthermore, FTS can also bring better and relevant results when you are searching a huge database.
To add a full-text search index to the students sample table, we can use the below MySQL command:
mysql>Alter table students ADD FULLTEXT (first_name, last_name);
mysql>Select * from students where match(first_name, last_name) AGAINST ('Ade');
In the above example, we have specified the columns that we want to be matched (first_name and last_name) against our search keyword ('Ade').
If we query the optimizer about the execution plan of the above query, we will get the following results:
mysql> explain Select * from students where match(first_name, last_name) AGAINST ('Ade');
+----+-------------+----------+------------+----------+---------------+------------+---------+-------+------+----------+-------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------+------------+----------+---------------+------------+---------+-------+------+----------+-------------------------------+
| 1 | SIMPLE | students | NULL | fulltext | first_name | first_name | 0 | const | 1 | 100.00 | Using where; Ft_hints: sorted |
+----+-------------+----------+------------+----------+---------------+------------+---------+-------+------+----------+-------------------------------+
It's clear that only a single row will be scanned even if our student's database has 500 rows and this will speed up the database.
Tip 6: Optimize Your Database Schema
Even if you optimize your MySQL queries and fail to come up with a good database structure, your database performance can still halt when your data increases.
Normalize Tables
First, normalize all database tables even if it will involve some trade-offs. For instance, if you are creating two tables to hold customers data and orders, you should reference the customer on the orders table using the customer id as opposed to repeating the customer's name on the orders table. The latter will cause your database to bloat.
The image below refers to a database schema that is designed for performance without any data redundancy. In MySQL database normalization, you should represent a fact only once in the entire database. Don't repeat the customer name in every table; instead just use the customer_Id for reference in other tables.
Image title
Also, always use the same data type for storing similar values even if they are on different tables, for instance, the schema above uses 'INT' data type to store 'customer_id' both in the customers and orders table.
Use Optimal Data Types
MySQL supports different data types including integer, float, double, date, date_time, Varchar, and text, among others. When designing your tables, you should know that "shorter is always better."
For instances, if you are designing a system user's table which will hold less than 100 users, you should use 'TINYINT' data type for the 'user_id' field because it will accommodate all your values from -128 to 128.
Also, if a field expects a date value (e.g. sales_order_date), using a date_time data type will be ideal because you don't have to run complicated functions to convert the field to date when retrieving records using SQL.
Use integer values if you expect all values to be numbers (e.g. in a student_id or a payment_id field). Remember, when it comes to computation, MySQL can do better with integer values as compared to text data types such as Varchar
Avoid Null Values
Null is the absence of any value in a column. You should avoid this kind of values whenever possible because they can harm your database results. For instance, if you want to get the sum of all orders in a database but a particular order record has a null amount, the expected result might misbehave unless you use MySQL 'ifnull' statement to return alternative value if a record is null.
In some cases, you might need to define a default value for a field if records don't have to include a mandatory value for that particular column/field.
Avoid Too Many Columns
Wide tables can be extremely expensive and require more CPU time to process. If possible, don't go above a hundred unless your business logic specifically calls for this.
Instead of creating one wide table, consider splitting it apart in to logical structures. For instance, if you are creating a customer table but you realize a customer can have multiple addresses, it is better to create a separate table for holding customers addresses that refer back to the customers table using the 'customer_id' field.
Optimize Joins
Always include fewer tables in your join statements. An SQL statement with poorly designed pattern that involves a lot of joins may not work well. A rule of thumb is to have utmost a dozen joins for each query.
Tip 7: MySQL Query Caching
If your website or application performs a lot of select queries (e.g. WordPress), you should take advantage of MySQL query caching feature. This will speed up performance when read operations are conducted.
The technology works by caching the select query alongside the resulting data set. This makes the query run faster since they are fetched from memory if they are executed more than once. However, if your application updates the table frequently, this will invalidate any cached query and result set.
You can check if your MySQL server has query cache enabled by running the command below:
mysql> show variables like 'have_query_cache';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| have_query_cache | YES |
+------------------+-------+
1 row in set (0.00 sec)
Setting the MySQL Server Query Cache
You can set the MySQL query cache values by editing the configuration file ('/etc/mysql/my.cnf' or '/etc/mysql/mysql.conf.d/mysqld.cnf'). This will depend on your MySQL installation. Don't set a very large query cache size value because this will degrade the MySQL server due to cached overhead and locking. Values in the range of tens of megabytes are recommended.
To check the current value, use the command below:
mysql> show variables like 'query_cache_%' ;
+------------------------------+----------+
| Variable_name | Value |
+------------------------------+----------+
| query_cache_limit | 1048576 |
| query_cache_min_res_unit | 4096 |
| query_cache_size | 16777216 |
| query_cache_type | OFF |
| query_cache_wlock_invalidate | OFF |
+------------------------------+----------+
5 rows in set (0.00 sec)
Then to adjust the values, include the following on the MySQL configuration file:
query_cache_type=1
query_cache_size = 10M
query_cache_limit=256k
You can adjust the above values according to your server needs.
The directive 'query_cache_type=1' turns MySQL caching on if it was turned off by default.
The default 'query_cache_size' is 1MB and like we said above a value a range of around 10 MB is recommended. Also, the value must be over 40 KB otherwise MySQL server will throw a warning, "Query cache failed to set size".
The default 'query_cache_limit' is also 1MB. This value controls the amount of individual query result that can be can be cached.
Conclusion
In this guide, we have shown you how to optimize your MySQL server hosted on Alibaba cloud for speed and performance.
We believe that the guide will allow you to craft better queries and have a well-structured database structure that will not only be simple to maintain but also offer more stability to your software applications or website.
https://dzone.com/articles/how-to-optimize-mysql-queries-for-speed-and-perfor
Thứ Năm, 30 tháng 6, 2016
Sự khác nhau giữa self và $this trong PHP
Thông thường để truy nhập vào một thuộc tính của một đối tượng, ta thường dùng $this. Nhưng khi truy xuất vào những thuộc tính static, có thể đối tượng đó chưa được khởi tạo nên ta không thể truy xuất qua $this được, bởi vậy ta cần dùng self để truy xuất.
Cú pháp: self::property
Tóm lại, $this sẽ trỏ tới đối tượng hiện thời còn self sẽ trỏ tới class hiện thời. Tức là sử dụng this->member cho non-static member và dùng self::$member cho static member.
Ví dụ:
1
2
3
4
5
6
7
8
9
10
11
12
13
| <?phpclass X { private $non_static_member = 1; private static $static_member = 2; function __construct() { echo $this->non_static_member . ' ' . self::$static_member; }}new X();?> |
Tuy nhiên, khi tạo lập tính đa hình (polymorphism) cho đối tượng, ta không thể dùng self để thay thế cho $this, ta có thể thấy rõ điều này trong ví dụ sau:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| <?phpclass X { function foo() { echo 'X::foo()'; } function bar() { $this->foo(); }}class Y extends X { function foo() { echo 'Y::foo()'; }}$x = new Y();$x->bar();?> |
Ở ví dụ này, khi ta dùng $this, class Y được kế thừa từ class X. Kết quả là nếu đối tượng được khởi tạo là X nó sẽ xuất ra kết quả là X::foo và nếu đối tượng được khởi tạo là Y nó sẽ xuất ra kết quả là Y::foo.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| <?phpclass X { function foo() { echo 'X::foo()'; } function bar() { self::foo(); }}class Y extends X { function foo() { echo 'Y::foo()'; }}$x = new Y();$x->bar();?> |
Còn khi dùng self để thay thế cho $this trong ví dụ trên, tính đa hình sẽ bị loại bỏ hoàn toàn bởi X::foo luôn luôn được gọi.
Đăng ký:
Bài đăng (Atom)