Có thể tôi không phải là người bạn cảm thấy yêu thương nhưng tôi cũng xin cảm ơn vì bạn đã có mặt trên đời và cho tôi biết rằng được yêu thương ai đó là điều hạnh phúc
Thứ Tư, 28 tháng 11, 2012
How to set or test connection string
Step 1: Open http://www.connectionstrings.com/
Step 2: Select Database
Step 3: Choose proper format of connection string of a particular provider.
Step 4: Replace you database information in connection string and use it.
Step 5: Still you are facing problem then problem is in your database information.
To check information, in windows
1. Start-> Run-> Type notepad
2. In notepad-> File->Save As -> Type “test.udl”
3. Now close test.udl and Right click on this file Icon and Click on properties
4. First select provider then go to Connection tab
5. Insert Database Information
6. Click on “Test Connection” Button
7. If It is not OK means database is not being accessed, update database information and put it in (step 4) connection string on which test connection succeeded.
OR
Open udl file in notepad again and see connection string.
Note: Password may be absent in connection string due to security purpose. so in this case It is needed to insert manually.
Hope, It helps.
(http://techbrij.com/203/how-to-set-or-test-connection-string)
Thứ Hai, 10 tháng 9, 2012
PDO là gì?
I. Giới thiệu về PDO:
PDO là cụm từ viết tắt của PHP Data Objects, có nghĩa là Các đối tượng dữ liệu trong PHP (đại loại thế). Đây là một thành phần mở rộng của PHP nhằm cung cấp cho chúng ta một cách thức đơn giản đề truy cập vào các CSDL khác nhau trong PHP.
Nếu như các bạn đã từng lập trình trên .Net, các bạn sẽ thấy một cái gọi là ADO (bản cũ) và ADO.Net, còn nếu các bạn đã từng code bằng Delphi, nó cũng có một món đồ chơi tương tự gọi là BDO, còn trên Java là JDBC... Về cơ bản thì mấy cái này nó giông giống nhau, mà bản chất là cung cấp một mô hình trừu tượng để truy cập tới CSDL. (Có thể coi nó như là một lớp (layer) trong lập trình đa lớp).
Cơ chế làm việc của những cái này có thể được mô hình hoá như sau:
Ứng dụng <----> PDO <---> Trình điều khiển các CSDL <---> Các truy vấn tới CSDL và kết quả trả về từ CSDL <---> CSDL (Access, MySQL, SQL Server, Oracle....).
Chúng ta có thể hình dung rằng mỗi một Hệ quản trị CSDL có một cách quản lý dữ liệu khác nhau, chẳng ai giống ai. Vì vậy, để truy xuất vào một loại CSDL nào đó, chúng ta cần phải khai báo trình điều khiển CSDL tương ứng với loại CSDL đó. Sau khi đã khai báo trình điều khiển, chúng ta có thể kết nối tới CSDL đó, tiến hành các truy vấn (có thể dựa trên ngôn ngữ truy vấn SQL, qua các Stored Procedure... mà CSDL đó hỗ trợ), lấy kết quả về rồi dùng các lệnh khác của PHP xử lý kết quả và hiển thị cho NSD.
II. Cài đặt PDO:
PDO chỉ xuất hiện trong PHP từ ver 5 chấm trở đi, vì vậy nếu như server của các bạn chỉ support dưới 5 chấm, hãy chịu khó update lên 5 chấm.
Sau khi cài đặt xong, chúng ta phải mở cái php.ini và enable thư viện này (nếu chưa có) cùng các trình điều khiển tới các CSDL liên quan.
VD dưới đây là dòng lệnh cấu hình trình điều khiển CSDL chạy trên Windows:
extension=php_pdo.dll
extension=php_pdo_firebird.dll
extension=php_pdo_informix.dll
extension=php_pdo_mssql.dll
extension=php_pdo_mysql.dll
extension=php_pdo_oci.dll
extension=php_pdo_oci8.dll
extension=php_pdo_odbc.dll
extension=php_pdo_pgsql.dll
extension=php_pdo_sqlite.dll
III. Thiết lập kết nối tới CSDL:
Đầu tiên, chúng ta cần phải biết rằng PDO thuần tuý là một lớp (class) được dùng để thao tác với CSDL. Vì vậy, nó cũng có các phương thức và thuộc tính như bất kỳ một lớp nào được xây dựng trên PHP.
PDO sử dụng một phương thức mặc định là __construct(). Phương thức này kiêm luôn nhiệm vụ tạo kết nối tới CSDL. Phương thức này có các tham số như sau:
PDO {
PDO __construct(string dsn,
string username,
string password,
array driver_options);
}
Trong đó:
- dsn (Data Source Name) là một chuỗi văn bản chứa các thông tin cần thiết để kết nối tới một CSDL xác định.
- username và password: chứa tên truy cập và mật khẩu của một tài khoản có quyền thao tác trên CSDL đó.
- driver_options là các tham số tuỳ chọn bổ sung nếu cần.
Cái DSN hơi khó nhớ một chút, và nó tuỳ thuộc vào loại CSDL. Nếu cần thiết thì các bạn chịu khó vào Google search. Ví dụ dưới đây là một chuỗi DSN kết nối tới CSDL MySQL:
'mysql:dbname=testdb;host=127.0.0.1';
Ví dụ:
<?php
$dbh = new PDO('mysql:host=localhost;dbname=thumotti', 'thumotti', 'thuhaiti');
?>
Đoạn mã trên tạo ra một biến $dbh (thể hiện của đối tượng PDO). Vì __construct là phương thức mặc định của PDO nên trong đoạn mã trên chúng ta không cần phải gọi tên phương thức này ra.
IV. Huỷ kết nối tới CSDL:
Để huỷ kết nối, đơn giản chúng ta chỉ việc gán instance của đối tượng đó với giá trị null.
VD:
<?php
$dbh = new PDO('mysql:host=localhost;dbname=thumotti', 'thumotti', 'thuhaiti');
$dbh=null
?>
V. Sử dụng PDO để truy vấn SQL:
Ở trên, các bạn đã biết cách kết nối và huỷ kết nối tới CSDL. Bây giờ chúng ta sẽ tiến hành thực hiện một truy vấn SQL thông qua PDO.
Để thực hiện một truy vấn SQL, chúng ta sử dụng một phương thức của PDO là exec().
PDO {
int exec(string statement);
}
Trong đó, statement là một câu lệnh SQL. Chú ý rằng câu lệnh SQL này phải chạy được trên CSDL mà ta đang sử dụng, (do mỗi một hệ quản trị CSDL lại có một vài câu lệnh SQL đặc chủng nên ta cần phải chú ý điều này). Phương thức trên trả về kết quả là số "râu" (row - record hay bản ghi) bị ảnh hưởng bởi câu lệnh SQL
Ví dụ dưới đây sử dụng để xoá một vài bản ghi nào đó:
<?php
$dbh = new PDO('mysql:host=localhost;dbname=thumotti', 'thumotti', 'thuhaiti');
$count = $dbh->exec("DELETE FROM users WHERE user_id<100"); // Xoá bỏ những "tên" có "số" nhỏ hơn 100.
print("Đã xoá bỏ $count người khỏi CSDL.\n");
?>
Nếu như các bạn làm theo những bước ở trên thì chưa đủ, ta phải tìm cách lấy dữ liệu trả về từ các query (VD như truy vấn Select chẳng hạn).
Để làm điều này, trước tiên chúng ta phải sử dụng một phương thức khác của PDO là PDO->query(). Phương thức này có nhiệm vụ thực thi một truy vấn SQL và trả về tập kết quả. Thường thì tập kết quả này sẽ được một lớp đối tượng khác là PDO Statement xử lý. Đây là tập các phương thức chuyên dụng để xử lý kết quả trả về, nó cũng gần giống như cái recordset vậy.
PDO {
PDOStatement query(string sql);
}
Các bạn cần chú ý phân biệt giữa hai phương thức exec() và query(). Exec() thực thi một truy vấn và trả về số các dòng bị ảnh hưởng bởi truy vấn, còn query() trả về một tập kết quả (thường là một recordset hoặc giá trị false). Người ta thường dùng exec() để truy vấn các câu lệnh như Insert, delete, update..., và dùng query() để truy vấn các câu lệnh Select.
Chúng ta có thể lấy kết quả ra theo hai cách: Lấy về từng dòng hay lấy về toàn bộ. Điểm đặc biệt là cũng như với các hàm xử lý MySQL, kết quả trả về thường được lưu trữ dưới dạng một mảng, rất thuận tiện và dễ dùng (hay nói ngắn gọn hơn là ... đại tiện ;D).
VI. Lấy kết quả về theo từng dòng:
Để lấy kết quả theo từng dòng (tương tự như hàm mysql_fetch_array()), chúng ta có thể sử dụng phương thức PDOStatement->fetch().
PDOStatement {
mixed fetch(int fetch_style,
int cursor_orientation,
int cursor_offset);
}
Hàm này sử dụng 3 tham số tuỳ chọn:
- Fetch_style xác định cách thức lấy dữ liệu. Nó có thể nhận một trong các giá trị sau:
PDO::FETCH_ASSOC: Trả về một mảng được đánh chỉ số bởi tên cột (field) (Tương tự như MYSQL_ASSOC)
PDO::FETCH_BOTH (mặc định): trả về một mảng được đánh chỉ số bởi tên cột và chỉ số số nguyên bắt đầu từ 0. (tương tự như MYSQL_BOTH)
PDO::FETCH_NUM: trả về một mảng được đánh chỉ số bởi số thứ tự của cột (xuất hiện trên query SELECT), bắt đầu = 0 (Tương tự như MYSQL_NUM)
... và một vài giá trị khác, tham khảo thêm trong manual, nhưng vì chưa đến lúc sờ đến nên CMXQ không liệt kê ở đây.
Cũng tương tự như mysql_fetch_array, phương thức này lấy một dòng từ vị trí con trỏ hiện tại và đẩy con trỏ sang dòng kế tiếp.
Ví dụ:
$dbh = new PDO('mysql:host=localhost;dbname=thumotti', 'thumotti', 'thuhaiti');
$stmt = $dbh->query("SELECT * FROM user where user_id<10") or die();
echo "<table>";
while (($row = $stmt->fetch(PDO::FETCH_ASSOC))) {
echo "<tr><td>${row['user_name']}<td>${row['e-mail']}\n";
}
echo "</table>";
VII. Lấy toàn bộ dữ liệu và đưa vào mảng:
Để thực hiện điều này, chúng ta cần phải sử dụng một phương thức khác thay cho fetch, đó là fetchall(). Cách thức dùng cũng tương tư nặng thằng fetch, chỉ có điều nó đưa tất cả dữ liệu vào một mảng.
Ví dụ:
$dbh = new PDO('mysql:host=localhost;dbname=thumotti', 'thumotti', 'thuhaiti');
$stmt = $dbh->query("SELECT * FROM user where user_id<10") or die();
$result=$stmt->fetchAll();
print_r($result);
Sử dụng Prepared statements:
Prepared statement có thể coi là 1 mẫu query được dịch sẵn với các tham số có thể thay đổi được.
Quá trình xử lý (parse/prepare) 1 query của database bao gồm việc phân tích, dịch và tối ưu query trước khi thực hiện nó. Sử dụng prepared statements, query chỉ phải parse 1 lần, sau đó ta có thể dùng lại nó nhiều lần với các tham số khác nhau mà không phải parse lại với mỗi lần thực hiện truy vấn như cách thông thường, nhờ đó sẽ tiết kiệm được tài nguyên và tăng tốc độ ứng dụng. Ngoài ra, sử dụng prepared statements còn giúp tránh được SQL injection.
Để tạo prepared statements, ta sử dụng phương thức: PDO->prepare()
class PDO {
PDOStatement prepare ( string statement [, array driver_options] )
}
Trong đó tham số statement là 1 chuỗi query có sử dụng các placeholder làm tham số đầu vào. Phương thức này trả về 1 đối tượng PDOStatement.
Ví dụ:
<?php
//Tạo database object
$dbh = new PDO('mysql:host=localhost;dbname=thumotti', 'thumotti', 'thuhaiti');
//Tạo prepared statement
$stmt = $dbh->prepare("INSERT INTO users (name, isMale) VALUES (:name, :ismale)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':ismale', $ismale);
// Thêm record
$name = 'Ácman';
$ismale = 1;
$stmt->execute();
// Thêm record
$name = 'cmxq';
Giải thích:
- Ở VD trên ta sử dụng :name, :ismale làm các placeholder, nơi sẽ nhận các giá trị cụ thể khi thực hiện query. Ngoài cách trên, ta có thể dùng ? làm placeholder. VD:
<?php
$stmt = $dbh->prepare("INSERT INTO users (name, isMale) VALUES (?, ?)");
?>
- Phương thức PDOStatement->bindParam() gắn placeholder với 1 biến, giống như PDOStatement->bindValue(). 2 phương thức này hoàn toàn giống nhau ngoại trừ việc bindParam() gắn biến theo tham chiếu. Placeholder khi được sử dụng dưới dạng ? sẽ được phân biệt bởi thứ tự của chúng. VD:
<?php
$stmt->bindParam(1, $name);
$stmt->bindParam(2, $ismale);
?>
- Phương thức PDOStatemen->execute() thực hiện câu lệnh prepared statement. Tham số truyền vào là 1 mảng. Nếu bỏ trống tham số, phương thức sẽ sử dụng giá trị của các biến mà ta đã gắn cho placeholder. VD:
<?php
$stmt->execute(array(':name'=>'Ácman', ':ismale'=>1));
$stmt->execute(array('cmxq', -1)); //Khi placeholder sử dụng ?
?>
Nguồn: http://phpvn.org/index.php/topic,544.0.html
Tham khảo: http://www.phpro.org/tutorials/Introduction-to-PHP-PDO.html
Thứ Ba, 3 tháng 4, 2012
WITH (NOLOCK) table hint equivalent for MySQL
The official SQL standard defines four isolation levels:
READ COMMITTED
READ UNCOMMITTED
REPEATABLE READ
SERIALIZABLE
Oracle, SQL Server and MySQL support isolation levels. During an operation, the database engine places certain locks to maintain data integrity. Different types of locking apply to different databases (Oracle vs. MySQL), or table types (eg. MyISAM vs. InnoDB).
When WITH (NOLOCK) is used with SQL Server, the statement does not place a lock nor honor exclusive locks on table. The MySQL equivalent is READ UNCOMMITTED, also known as “dirty read” because it is the lowest level of isolation. If we specify a table hint then it will override the current default isolation level. MySQL default isolation level is REPEATABLE READ which means locks will be placed for each operation, but multiple connections can read data concurrently.
SQL Server WITH (NOLOCK) looks like this:
SELECT * FROM TABLE WITH (nolock)
To achieve the same with MySQL, we change the session isolation mode using the SET SESSION command.
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;
SELECT * FROM TABLE_NAME ;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ ;
This statement will work similar to WITH (NOLOCK) i.e READ UNCOMMITTED data. We can also set the isolation level for all connections globally:
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;
In addition, two system variables related to isolation also level exist in MySQL server:
SELECT @@global.tx_isolation; (global isolation level)
SELECT @@tx_isolation; (session isolation level)
Or set the isolation level inside a transaction:
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
GO
(http://www.itecsoftware.com/with-nolock-table-hint-equivalent-for-mysql)
Thứ Sáu, 28 tháng 10, 2011
Connection Strings
- .NET Data Providers
- OLE DB Data Providers
- Active Directory Service
- Advantage
- AS/400 (from IBM)
- AS/400 and VSAM (from Microsoft)
- Commerce Server
- DB2
- DTS Packages
- Exchange
- Excel
- Internet Publishing
- Index Server
- Microsoft Jet (Access)
- Microsoft Project
- MySQL
- ODBC Databases
- OLAP Services
- Oracle (from Microsoft)
- Oracle (from Oracle)
- Pervasive
- Simple Provider
- SQLBase
- SQL Server
- SQL Server via SQL XML Ole Db
- Sybase Adaptive Server Anywhere
- Sybase Adaptive Server Enterprise
- Text Files
- UniData and UniVerse
- Visual FoxPro
- ODBC DSN
- OLE DB Data Link
- ODBC DSN-Less
- Data Shape Provider
- ADO URL
- MS Remote Provider
- Remote Data Service (RDS)
Thứ Bảy, 2 tháng 7, 2011
Tối ưu hóa truy vấn MySQL cho site có lượng truy cập lớn
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... :ohmy: 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:
$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
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 :innocent:? Chắc do nó là advanced nên mới thế :emlaugh:. - Giải quyết vấn đề:
// 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:
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. Chúc các bạn học tốt
Phần đọc thêm
1. Paging/chunked data retrieval to limit
2. Don’t use SELECT *
3. Be wary of lots of small quick queries if a longer query can be more efficient
+ Use EXPLAIN to profile the query execution plan
+ Use Slow Query Log (always have it on!)
+ Don’t use DISTINCT when you have or could use GROUP BY
+ Use proper data partitions
1. For Cluster. Start thinking about Cluster *before* you need them
+ Insert performance
1. Batch INSERT and REPLACE
2. Use LOAD DATA instead of INSERT
+ LIMIT m,n may not be as fast as it sounds
+ Don’t use ORDER BY RAND() if you have > ~2K records
+ Use SQL_NO_CACHE when you are SELECTing frequently updated data or large sets of data
+ avoid wildcards at the start of LIKE queries
+ avoid correlated subqueries and in select and where clause (try to avoid in)
+ config params –
+ no calculated comparisons — isolate indexed columns
+ innodb_flush_commit=0 can help slave lag
+ ORDER BY and LIMIT work best with equalities and covered indexes
+ isolate workloads don’t let administrative work interfere with customer performance. (ie backups)
+ use optimistic locking, not pessimistic locking. try to use shared lock, not exclusive lock. share mode vs. FOR UPDATE
+ use row-level instead of table-level locking for OLTP workloads
+ Know your storage engines and what performs best for your needs, know that different ones exist.
1. use MERGE tables ARCHIVE tables for logs
+ Optimize for data types, use consistent data types. Use PROCEDURE ANALYSE() to help determine if you need less
+ separate text/blobs from metadata, don’t put text/blobs in results if you don’t need them
+ if you can, compress text/blobs
+ compress static data
+ don’t back up static data as often
+ derived tables (subqueries in the FROM clause) can be useful for retrieving BLOBs w/out sorting them. (self-join can speed up a query if 1st part finds the IDs and use it to fetch the rest)
+ enable and increase the query and buffer caches if appropriate
+ ALTER TABLE…ORDER BY can take chronological data and re-order it by a different field
+ InnoDB ALWAYS keeps the primary key as part of each index, so do not make the primary key very large, be careful of redundant columns in an index, and this can make the query faster
+ Do not duplicate indexes
+ Utilize different storage engines on master/slave ie, if you need fulltext indexing on a table.
+ BLACKHOLE engine and replication is much faster than FEDERATED tables for things like logs.
+ Design sane query schemas. don’t be afraid of table joins, often they are faster than denormalization
+ Don’t use boolean flags
+ Use a clever key and ORDER BY instead of MAX
+ Keep the database host as clean as possible. Do you really need a windowing system on that server?
+ Utilize the strengths of the OS
+ Hire a MySQL ™ Certified DBA
+ Know that there are many consulting companies out there that can help, as well as MySQL’s Professional Services.
+ Config variables & tips:
1. use one of the supplied config files
2. key_buffer, unix cache (leave some RAM free), per-connection variables, innodb memory variables
3. be aware of global vs. per-connection variables
4. check SHOW STATUS and SHOW VARIABLES (GLOBAL|SESSION in 5.0 and up)
5. be aware of swapping esp. with Linux, “swappiness” (bypass OS filecache for innodb data files, innodb_flush_method=O_DIRECT if possible (this is also OS specific))
6. defragment tables, rebuild indexes, do table maintenance
7. If you use innodb_flush_txn_commit=1, use a battery-backed hardware cache write controller
8. more RAM is good so faster disk speed
9. use 64-bit architectures
+ Know when to split a complex query and join smaller ones
+ Debugging sucks, testing rocks!
+ Delete small amounts at a time if you can
+ Archive old data — don’t be a pack-rat! 2 common engines for this are ARCHIVE tables and MERGE tables
+ use INET_ATON and INET_NTOA for IP addresses, not char or varchar
+ make it a habit to REVERSE() email addresses, so you can easily search domains
+ –skip-name-resolve
+ increase myisam_sort_buffer_size to optimize large inserts (this is a per-connection variable)
+ look up memory tuning parameter for on-insert caching
+ increase temp table size in a data warehousing environment (default is 32Mb) so it doesn’t write to disk (also constrained by max_heap_table_size, default 16Mb)
+ Normalize first, and denormalize where appropriate.
+ Databases are not spreadsheets, even though Access really really looks like one. Then again, Access isn’t a real database
+ In 5.1 BOOL/BIT NOT NULL type is 1 bit, in previous versions it’s 1 byte.
+ A NULL data type can take more room to store than NOT NULL
+ Choose appropriate character sets & collations — UTF16 will store each character in 2 bytes, whether it needs it or not, latin1 is faster than UTF8.
+ make similar queries consistent so cache is used
+ Have good SQL query standards
+ Don’t use deprecated features
+ Use Triggers wisely
+ Run in SQL_MODE=STRICT to help identify warnings
+ Turning OR on multiple index fields (<5.0) into UNION may speed things up (with LIMIT), after 5.0 the index_merge should pick stuff up.
+ /tmp dir on battery-backed write cache
+ consider battery-backed RAM for innodb logfiles
+ use min_rows and max_rows to specify approximate data size so space can be pre-allocated and reference points can be calculated.
+ as your data grows, indexing may change (cardinality and selectivity change). Structuring may want to change. Make your schema as modular as your code. Make your code able to scale. Plan and embrace change, and get developers to do the same.
+ pare down cron scripts
+ create a test environment
+ try out a few schemas and storage engines in your test environment before picking one.
+ Use HASH indexing for indexing across columns with similar data prefixes
+ Use myisam_pack_keys for int data
+ Don’t use COUNT * on Innodb tables for every search, do it a few times and/or summary tables, or if you need it for the total + of rows, use SQL_CALC_FOUND_ROWS and SELECT FOUND_ROWS()
+ use –safe-updates for client
+ Redundant data is redundant
+ Use INSERT … ON DUPLICATE KEY update (INSERT IGNORE) to avoid having to SELECT
+ use groupwise maximum instead of subqueries
+ be able to change your schema without ruining functionality of your code
+ source control schema and config files
+ for LVM innodb backups, restore to a different instance of MySQL so Innodb can roll forward
+ use multi_query if appropriate to reduce round()-trips
+ partition appropriately
+ partition your database when you have real data
+ segregate tables/databases that benefit from different configuration variables
(http://www.miendatweb.com/home/post-toi-uu-hoa-truy-van-mysql-cho-site-co-luong-truy-cap-lon-323.html)