Web applications are growing very rapidly, below is the graph showing the increase in number of web applications since 2000

0. Cache results for mysql statements.

This is one of the major step if you are not having a static website(a bunch of HTML pages). If your main/home/landing pages have any dynamic data, coming directly from a database it's always better to cache the result set of the query so when any other client requests the same page you can serve it from the cache. Although you will be needing some special handling for invalidating the cache when result set updates i.e., at the time of insertions and updations.

This way you can improve the performance and speed of your web application almost by 60%.

P.S - Do not exploit this method, as if you are not handling your cache correctly it might also blow up you web application and decrease performance instead of increasing it. Always cache only what is important, otherwise you may be  running out of cache store too soon. Cache memory like memcache automatically deletes older files, but still remember the saying:

With great power come's great responsibilities

1. Avoid too many joins in a query and use subqueries instead

This is a debatable topic as sometimes joins will perform better and sometimes subqueries and selection of one method over another is purely dependent on the use case. One bad use case can be this

SELECT table1_id, table2_name, table3_name, table4_name, 
table5_name, table6_name, table7_name, table8_name
FROM t1 
LEFT JOIN table2 ON (table1_id = table2_id) 
LEFT JOIN table3 ON (table3_id = table1_id) 
LEFT JOIN table4 ON (table4_id = table1_id)
LEFT JOIN table5 ON (table5_id = table1_id)
LEFT JOIN table6 ON (table6_id = table1_id)
LEFT JOIN table7 ON (table7_id = table1_id)
LEFT JOIN table8 ON (table8_id = table1_id)

The query above is surely to perform slow and as soon as data shoots beyond a limit, it might not even give result and your system will run out of memory.

A better approach which performs a lot better is a subquery

SELECT table1_id,
(select table2_name from table2 where table1_id = table2_id),
(select table3_name from table3 where table1_id = table3_id),
(select table4_name from table4 where table1_id = table4_id),
(select table5_name from table5 where table1_id = table5_id),
(select table6_name from table6 where table1_id = table6_id),
(select table7_name from table7 where table1_id = table7_id),
(select table8_name from table8 where table1_id = table8_id),  
FROM table1

2.  Use pagination wherever possible ALWAYS

Do not try to show all the content on a single page and always use pagination when showing up tabular data or matrix. Limiting the result set is always good practise and improves performance dramatically. You can load results which can be shown in the current viewport of the user and prefetch the next result set so that user never really sees the lag.

3. Parallelise download.

Web browsers have limit to send 6 concurrent requests per domain, i.e it can get only 6 responses at a time and rest will be blocked until these 6 completes and then next set of 6 requests this applies to XHR, images, scripts, links or any additional request.

In order to increase this limit for your website it better to host content on different servers and have different urls. Static content like images, JS and CSS can be hosted on 3 different CDN domains. Amazon AWS provide feature to have different urls pointing to same bucket.

4. Concatenate and  Minimise your javascript and css

Instead of having different files for css and javascript based on modules it is always good practise to concatenate all files into single file when deploying changes on production. This will help you reduce number of calls made on page load and also reduce the number of handshakes done between client and server. Minification is process of removing spaces, comments and renaming local parameters of a function to reduce the file size of javascript and css. Lesser the file size faster is the download.

5. Use CDN

CDN's are high performance content delivery network that have server's all around the world. Whenever the content is requested from CDN, it checks your location and gives you content from the nearest server.
\nAnother advantages of CDN's are that browser's cache the resource for a domain, so if another web application is using same CDN, browser might have cached the content and anyone visiting your website will also be served content from cache.

6. Cache static resources.

Always set Expiry Header to far future and Cache control for almost a week for static resources like js/css/images. This can be easily done in config for web servers like Apache/ngnix.

7. Use Sprites instead of separate images

Instead of loading multiple images on same page and making too many calls it is always better use sprites and loading all the images required on page in a single request and using css to position and display part of that image

8. Load above the fold content first and lazily load rest of the page.

Above the fold content is what user see's at first on loading the web application, Prioritise above the fold content and load only that part first and below the fold content can be then lazily loaded.

9. Enable gzip compression on server

Before sending response from server it is always good practise to compress the response using gzip which reduces the payload dramatically. It can be easily configured in any of the web servers present