Today, database operations are increasingly becoming a performance bottleneck for the entire application, especially for Web applications. As for the performance of the database, this is not just something that DBAs need to worry about, and that's what we programmers need to focus on. When we design the database table structure, we need to pay attention to the performance of the data operation when we operate the database (especially the SQL statement when we check the table). Here, we don't talk too much about the optimization of SQL statements, but only for MySQL, the most web-application database. Hopefully, the following optimization techniques will be useful to you.
1. Optimize your query for query caching
Most MySQL servers have query caching turned on. This is one of the most effective ways to improve sex, and it is handled by the MySQL database engine. When many of the same queries are executed many times, the query results are placed in a cache so that subsequent queries do not directly access the cached results without the action table.
The main problem here is that it's easy to ignore for programmers. Because some of our query statements will let MySQL not use caching. Take a look at the following example:
The query cache does not open
$r = mysql_query ("Select username from user WHERE signup_date >= curdate ()");
Open Query Cache
$today = date ("y-m-d");
$r = mysql_query ("Select username from user WHERE signup_date >= ' $today '");
The difference between the two SQL statements above is curdate (), and MySQL's query cache does not work on this function. So, like now () and RAND () or some other SQL functions, they don't open the query cache because the return of these functions is variable. So all you need is to use a variable instead of the MySQL function to turn on the cache.
2. EXPLAIN your SELECT query
Use the EXPLAIN keyword to let you know how MySQL handles your SQL statements. This can help you analyze your query statements or the performance bottlenecks of the table structure.
EXPLAIN's query results will also tell you how your index keys are being used, how your data tables are searched and sorted ... Wait, wait.
Pick one of your SELECT statements (recommend picking the most complex, multiple table joins) and add the keyword explain to the front. Then, you'll see a table. In the following example, we forget to add the group_id index and have a table join:
When we index the group_id field:
As we can see, the previous result shows a search of 7883 rows, and the last one searches only 9 and 16 rows of two tables. Viewing the Rows column allows us to identify potential performance issues.
3. Use LIMIT 1 when only one row of data is used
There are times when you query the table and you already know that there will only be one result, but because you may need to fetch the cursor, or you might check the number of records returned.
In this case, adding LIMIT 1 can increase performance. In this way, the MySQL database engine stops searching after finding a piece of data, rather than continuing to look back at the next record-keeping data.
The following example, just to find out if there are "China" users, it is obvious that the latter will be more efficient than the previous one. (Note that the first one is select * and the second is select 1)
Inefficient:
$r = mysql_query ("SELECT * from user WHERE country = ' the '");
if (mysql_num_rows ($r) > 0) {
//...
}
Efficient:
$r = mysql_query ("Select 1 from user WHERE country = ' LIMIT 1");
if (mysql_num_rows ($r) > 0) {
//...
}
4. Jianjian Index for search word
An index is not necessarily a primary key or a unique field. If you have a field in your table that you will always use to do a search, then make an index of it.
From above you can see the search string "last_name like ' a% '", one is indexed, one is no index, performance is about 4 times times worse.
In addition, you should also need to know what kind of search can not use the normal index. For example, when you need to search for a word in a large article, such as "WHERE post_content like '%apple% '", indexing can be meaningless. You may need to use a MySQL Full-text index or make an index yourself (say: search keywords or tag or something)
5. Use an example of a similar type in a join table and index it
If your application has a lot of join queries, you should be sure that the fields of join in the two tables have been indexed. In this way, within MySQL, you will start a mechanism to optimize the SQL statements for your join.
Also, these fields that are used for joins should be of the same type. For example, if you were to join a DECIMAL field with an INT field, MySQL would not be able to use their index. For those string types, it is also necessary to have the same character set. (The character set of two tables may not be the same)
Find company $r in state
= mysql_query ("Select Company_Name from users left
JOIN companies" (Users.state = Compani es.state)
WHERE users.id = $user _id ");
The two state fields should be indexed, and should be of comparable type, the same character set.
6. Never order by RAND ()
Want to disrupt the returned data row? Pick a random data? I don't know who invented the usage, but many beginners like it. But you don't know what a terrible performance problem this is.
If you really want to disrupt the data rows that you've returned, there are n ways you can achieve that. Using this allows you to have an exponential decline in the performance of your database. The problem here is that MySQL will have to perform the rand () function (CPU time), and this is for each row of records to be recorded and then sorted. Even if you use the limit 1 it doesn't help (because you want to sort)
The following example randomly picks a record
Do not do this:
$r = mysql_query ("Select username from user order by RAND () LIMIT 1");
This is going to be better:
$r = mysql_query ("SELECT count (*) from user");
$d = Mysql_fetch_row ($r);
$rand = Mt_rand (0, $d [0]-1);
$r = mysql_query ("Select username from user LIMIT $rand, 1");
7. Avoid SELECT *
The more data you read from the database, the slower the query will become. And, if your database server and Web server are two separate servers, this will also increase the load on the network transport.
So, you should develop a good habit of taking whatever you need.
$r = mysql_query ("SELECT * from user WHERE user_id = 1") is not recommended;
$d = Mysql_fetch_assoc ($r);
echo "Welcome {$d [' username ']}";
Recommended
$r = mysql_query ("Select username from user WHERE user_id = 1");
$d = Mysql_fetch_assoc ($r);
echo "Welcome {$d [' username ']}";
8. Always set an ID for each table
We should set an ID for each table in the database as its primary key, and the best is an int type (recommended to use unsigned) and set up an automatically added Auto_increment flag.
Even if it's you. The Users table has a field with a primary key called "email," and you don't let it be the primary key. Using the VARCHAR type to use as a primary key can degrade performance. In addition, in your program, you should use the ID of the table to construct your data structure.
Also, under the MySQL data engine, there are some operations that require the use of primary keys, in which case the performance and settings of the primary key become very important, such as clustering, partitioning ...
Here, only one exception is the "foreign key" of the association table, that is, the primary key of the table, which is composed of the primary keys of several other tables. We call this the "foreign key". For example: There is a "student table" with the student ID, there is a "timetable" with the course ID, then the "score sheet" is the "association table", which is associated with the student table and curriculum, in the score sheet, the student ID and course ID is called "foreign key" which together form the primary key.
9. Use ENUM instead of VARCHAR
The ENUM type is very fast and compact. In practice, it saves TINYINT, but its appearance is displayed as a string. As a result, using this field to make a list of options becomes quite perfect.
If you have a field, such as "gender", "Country", "nation", "state" or "department", you know that the values of these fields are limited and fixed, then you should use an ENUM instead of a VARCHAR.
MySQL also has a "suggestion" (see article tenth) that tells you how to rearrange your table structure. When you have a VARCHAR field, this suggestion will tell you to change it to an ENUM type. Use PROCEDURE analyse () you can get relevant advice.
10. Recommendations from PROCEDURE analyse ()
PROCEDURE analyse () will let MySQL help you analyze your field and its actual data, and will give you some useful advice. These recommendations become useful only if you have actual data in the table, because there are some big decisions that need to be based on data.
For example, if you create an INT field as your primary key, however there is not much data, then PROCEDURE analyse () will suggest that you change the type of the field to Mediumint. Or you use a VARCHAR field, because there's not much data, you might get a suggestion to change it to an ENUM. All these proposals may be due to the fact that there is not enough data, so the decision-making is not accurate enough.
In phpMyAdmin, you can view these suggestions by clicking "Propose table Structure" while viewing the table.
It is important to note that these are only suggestions that will become accurate only when the data in your table is growing. Be sure to remember that you are the last person to make a decision.
11. Use not NULL as much as possible
Unless you have a very special reason to use null values, you should always keep your fields not NULL. This may seem a bit controversial, please look down.
First, ask yourself how different the "Empty" and "null" are (if it is int, that is 0 and null)? If you feel that there is no difference between them, then you should not use NULL. (You know what?) In Oracle, NULL and Empty strings are the same! )
Do not assume that NULL does not require space and that it requires extra space, and that your program will be more complex when you compare it. Of course, this is not to say that you cannot use NULL, the reality is very complex, there will still be some cases, you need to use null values.
The following is excerpted from MySQL's own documentation:
Copy Code code as follows:
"NULL columns require additional spaces in the row to record whether their values are NULL. For MyISAM tables, each NULL column takes one bit extra and rounded up to the nearest byte.
Prepared statements
Prepared statements is like a stored procedure, a collection of SQL statements running in the background, and we can derive a lot of benefits from using Prepared statements, whether it's a performance issue or a security issue.
Prepared statements can check some of the variables you bind so that you can protect your program from "SQL injection" attacks. Of course, you can also manually check your variables, however, manual checks are prone to problems and are often forgotten by programmers. This is a better problem when we use some framework or ORM.
In terms of performance, when an identical query is used more than once, this can give you a considerable performance advantage. You can define some parameters for these prepared statements, and MySQL will parse it only once.
Although the latest version of MySQL in the transmission prepared statements is using the binary situation, so this will make the network transport very efficient.
There are, of course, some cases where we need to avoid using prepared statements because it does not support query caching. But it is said that version 5.1 was supported later.
To use prepared statements in PHP, you can view its manual: Mysqli extensions or use of database abstraction layers, such as: PDO.
Create PREPARED Statement
if ($stmt = $mysqli->prepare ("Select username from user WHERE state=?") {
//binding parameter
$stmt->bind_param ("s", $state);
Implementation of the
$stmt->execute ();
Binding result
$stmt->bind_result ($username);
Mobile cursor
$stmt->fetch ();
printf ("%s is from%s\n", $username, $state);
$stmt->close ();
}
13. No buffer query
Normally, when you execute an SQL statement in your script, your program stops there until the SQL statement is returned, and then your program continues to execute. You can use the no buffer query to change this behavior.
In this case, there is a very good description in the PHP Documentation: the Mysql_unbuffered_query () function:
Copy Code code as follows:
"Mysql_unbuffered_query () sends the SQL query query to MySQL without automatically fetching and buffering the result rows As mysql_query () does. This saves a considerable amount of memory with SQL queries that produce large the result sets, and the can start working on t He result set immediately after the the "I" has been retrieved as you don ' t have to wait until the complete SQL query ha s been performed. "
The above sentence translates to say that mysql_unbuffered_query () sends an SQL statement to MySQL instead of automatically fethch and caches the results like mysql_query (). This can save a lot of considerable memory, especially those that produce a lot of results, and you don't have to wait until all the results are returned, and you can start working on the query results right away when the first row of data returns.
However, there are some limitations. Because you either read all the rows or you want to call Mysql_free_result () to clear the results before you make the next query. Also, mysql_num_rows () or Mysql_data_seek () will not be available. Therefore, you need to consider carefully whether to use a query without buffering.
14. Save IP Address as UNSIGNED INT
Many programmers create a VARCHAR (15) field to hold a string of IP instead of a reshaped IP. If you use plastic to store, you need only 4 bytes, and you can have a fixed-length field. Also, this gives you the advantage of the query, especially if you need to use the Where condition: IP between Ip1 and IP2.
We have to use the unsigned INT because the IP address uses the entire 32-bit unsigned integer.
And your query, you can use Inet_aton () to convert a string IP into an integer and use Inet_ntoa () to turn an integer into a string IP. In PHP, there are also functions such as Ip2long () and Long2ip ().
Copy Code code as follows:
$r = "UPDATE users SET IP = Inet_aton (' {$_server[' remote_addr ']} ') WHERE user_id = $user _id";
15. Fixed-length table will be faster
If all the fields in the table are of fixed length, the entire table is considered "static" or "Fixed-length". For example, there are no fields of the following type in the table: Varchar,text,blob. As long as you include one of these fields, the table is not a "fixed-length static table", so that the MySQL engine handles it in another way.
Fixed-length tables can improve performance because MySQL searches faster because these fixed lengths can easily compute the next data offset, so the readings will be quick. And if the field is not fixed long, then, each time to find the next one, you need the program to find the primary key.
Also, fixed-length tables are more easily cached and rebuilt. However, the only side effect is that fixed-length fields waste a bit of space, because a set of long fields, whether you use it or not, he has to allocate so much space.
Using the vertical split technique (see next), you can split your table into two that are fixed-length and one that is indefinite.
16. Vertical Segmentation
Vertical segmentation is a way to change a table in a database into several tables, which can reduce the complexity of the table and the number of fields to achieve optimization. (Previously, in a bank project, saw a table has more than 100 fields, very scary)
Example one: There is a home address in the Users table, this field is an optional field, and you do not need to read or overwrite this field frequently, except for personal information while you are operating the database. So why not put him in the other table? This will make your table have better performance, we think is not, a lot of time, I for the user table, only the user ID, username, password, user role, etc. will be often used. Smaller tables always have good performance.
Example two: You have a field called "Last_login" that will be updated every time a user logs on. However, each update causes the table's query cache to be emptied. So, you can put this field in another table so that it doesn't affect your constant reading of the user ID, username, and user role, because the query cache will help you to add a lot of performance.
Also, you need to be aware that the tables that are formed by the separated fields do not frequently join them, otherwise, this performance will be worse than the undivided, and it will be a drop in the extreme number.
17. Split large DELETE or INSERT statement
If you need to perform a large DELETE or INSERT query on an online Web site, you need to be very careful to avoid your actions so that your entire site stops accordingly. Because these two operations will lock the table, the table is locked, no other operation can enter.
Apache will have a lot of child processes or threads. So, it works fairly efficiently, and our servers don't want to have too many child processes, threads and database links, which are great for server resources, especially memory.
If you lock your watch for a while, for example, 30 seconds, then for a highly visited site, this 30-second accumulation of access process/thread, database links, open files, may not only let you crash Web services, but also may let your entire server immediately hanging.
So, if you have a big deal, you're going to have to split it up, and using the LIMIT condition is a good way to do it. Here is an example:
while (1) {
//1000 mysql_query per session
("DELETE from logs WHERE log_date <= ' 2009-11-01 ' LIMIT 1000");
if (mysql_affected_rows () = = 0) {
//no delete, quit! Break
;
Take a break every time
usleep (50000);
}
18. The smaller the column, the quicker it will be.
For most database engines, hard disk operations can be the most significant bottleneck. So, getting your data compact can be very helpful in this case, because it reduces access to the hard disk.
See the MySQL documentation Storage Requirements View all data types.
If a table has only a few columns (for example, a dictionary table, a configuration table), then we have no reason to use INT to make the key, using Mediumint, SMALLINT or smaller TINYINT will be more economical. If you don't need to record time, using DATE is much better than DATETIME.
Of course, you also need to leave enough space for expansion, otherwise, you will do this later, you'll die very difficult to see, refer to the example of Slashdot (November 06, 2009), a simple ALTER TABLE statement took 3 hours, because there are 16 million data.
19. Choose the right storage engine
There are two storage engines MyISAM and InnoDB in MySQL, and each engine has its pros and cons. Cool Shell before the article "Mysql:innodb or MyISAM?" Discussion and this matter.
MyISAM is suitable for some applications that require a large number of queries, but it is not good for a large number of write operations. Even you just need to update a field, the entire table will be locked up, and other processes, the read process can not operate until the read operation is complete. In addition, MyISAM is extremely fast for calculations such as SELECT COUNT (*).
The InnoDB trend will be a very complex storage engine, and for some small applications it will be slower than MyISAM. He is it supports "row lock", so in write operation more of time, will be more outstanding. And, he also supports more advanced applications, such as: transactions.
Here's a MySQL manual.
target= "_blank" MyISAM Storage Engine
InnoDB Storage Engine
20. Use an Object-relational mapper (relational Mapper)
Using ORM (Object relational Mapper), you can gain a reliable performance increase. All the things an ORM can do can be written out manually. However, this requires a senior expert.
ORM's most important is "Lazy Loading", that is to say, only when the need to fetch value of the time will go to really do. But you also need to be careful about the side effects of this mechanism, because it's very likely that it will degrade performance by creating lots and lots of small queries.
ORM can also package your SQL statements into a single transaction, which is much faster than executing them alone.
At present, the personal favorite of the PHP orm is: Doctrine.
21. Beware of "permanent links"
The purpose of "permanent link" is to reduce the number of times you re-create a MySQL link. When a link is created, it will always be in the state of the connection, even if the database operation is over. And since our Apache began reusing its subprocess-that is, the next HTTP request will reuse the Apache subprocess and reuse the same MySQL link.
PHP Manual: Mysql_pconnect ()
In theory, this sounds very good. But from personal experience (and also for most people), this feature creates more trouble. Because, you only have a limited number of links, memory problems, file handles number, and so on.
Also, Apache runs in extremely parallel environments and creates many, many processes. This is why this "permanent link" mechanism does not work well. Before you decide to use a "permanent link," you need to consider the architecture of your entire system.
The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.