I am having difficulties because of the database structure on a game website similar to http://box10.com.
I attempted to change table structure a bit but I made it worse, and now I must not do another mistake to keep my client. So I am scared to make any change.
If you can help me I will be extremely appreciated. I didn’t want to write my attemts and my thougts on configuration not to take more of your time.
There are two tables related with my question.
CREATE TABLE `_games` (
`id` INT(6) NOT NULL AUTO_INCREMENT,
`title` VARCHAR(100) NOT NULL,
`perma` VARCHAR(100) NOT NULL,
`approve` TINYINT(1) NOT NULL DEFAULT '0',
`tags` MEDIUMTEXT NOT NULL,
`description` MEDIUMTEXT NOT NULL,
INDEX `id` (`id`),
INDEX `approve` (`approve`),
FULLTEXT INDEX `ad` (`title`)
)
ENGINE=MyISAM
ROW_FORMAT=DEFAULT
AUTO_INCREMENT=15000
CREATE TABLE `_searches` (
`id` INT(10) NOT NULL AUTO_INCREMENT,
`term` VARCHAR(200) NOT NULL DEFAULT '',
`viewcount` INT(10) NOT NULL DEFAULT '0',
`date` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
ROW_FORMAT=DEFAULT
AUTO_INCREMENT=450000
Usage of _searches table:
On search pages, I insert the search term to _searches table if the term doesn’t exists. If it exists, then I update the date and viewcount.
$date = date("Y-m-d G:i:s");
$c = mysql_query("SELECT id FROM _searches WHERE term='$term'");
if (mysql_num_rows($c) == 1) {
mysql_query("update _searches set viewcount=viewcount+1,date='$date' WHERE term='$term'");
} else {
mysql_query("insert into _searches (term,viewcount,date) values ('$term',1,'$date')");
}
When I use codes above, mysqld CPU usage goes up to around %500 from %50 and load goes up to 7 from 0.7.
Can you please share some suggestions to help me?
Usage of _games table:
On tag pages, I use following sql to get records: (e.g. y8.com/tags/Action)
SELECT title,perma FROM _games WHERE tags LIKE '%action,%' AND approve=0 order by id desc LIMIT 0, 20
On search pages, to search games:
SELECT perma,title, MATCH(title) AGAINST('$term') AS sort
FROM _games WHERE MATCH(title) AGAINST('$term' IN BOOLEAN MODE) and approve=0
ORDER BY sort DESC limit 10
On “related games” sections of game pages: (e.g. http://www.oyunlar1.com/online.php?flash=5661)
SELECT perma,title, MATCH(title) AGAINST('mario kills the bad guy') AS sort
FROM _games WHERE MATCH(title) AGAINST('mario kills the bad guy' IN BOOLEAN MODE) and approve=0
ORDER BY sort DESC limit 10
On home page to get records:
SELECT title,perma FROM _games where approve=0 order by id desc LIMIT 0,28
On game pages to get game information:
SELECT title,description FROM _games WHERE perma='mario-kills-the-bad-guy' AND approve=0
my.cnf file:
[mysqld]
set-variable=local-infile=0
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
# Default to using old password format for compatibility with mysql 3.x
# clients (those using the mysqlclient10 compatibility package).
old_passwords=1
# Performance optimization
skip-external-locking
max_connections = 300
key_buffer = 8M
sort_buffer = 1M
join_buffer_size = 256K
max_allowed_packet = 1M
thread_stack = 128K
thread_cache_size = 2
table_cache = 1024
thread_concurrency = 2
query_cache_limit = 128k
query_cache_size = 4M
# InnoDB optimization
innodb_file_per_table
innodb_flush_log_at_trx_commit = 0
innodb_lock_wait_timeout = 30
innodb_thread_concurrency = 2
innodb_locks_unsafe_for_binlog = 1
innodb_table_locks = 0
innodb_log_file_size = 2M
innodb_buffer_pool_size = 128M
# !!!! do not change next 2 values !!!!
# data will get destroyed unless you backup everything before changing and then import it back.
innodb_additional_mem_pool_size = 32M
innodb_log_buffer_size = 256k
# Disabling symbolic-links is recommended to prevent assorted security risks;
# to do so, uncomment this line:
# symbolic-links=0
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
Server:
CentOS 5 (64-bit) (CEN564) Plesk 9.5
Quad-Xeon 3220 / 8GB memory / 2x250GB SATAII / 10TB BW / 1GiGE / 8 IPS (SoftLayer)
MySQL 5.0.77
Server receives around 500,000 pageviews a day.
I am open to every kind of suggestion, thank you for your time.
2
Answers
instead of
you can write
also i see that, you don’t have a index at “term” field… selecting from non-indexed field can cause this problem too..
and never forget that, full text search is always slow… can you install a full text search engine like sphinx (http://sphinxsearch.com/) or solr (http://lucene.apache.org/solr/) and also caching to memory with memcache or apc will definitly help you.
The obvious problem with your _searches table is that there is no index on the ‘term’ column by which you are searching. So you should start by adding an index (perhaps unique also, I will explain below why)
ie:
This will speed up very much your select query. Also you could improve the if statement below by using
INSERT DELAYED
(http://dev.mysql.com/doc/refman/5.5/en/insert-delayed.html) andON DUPLICATE KEY UPDATE
(http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html). For this to work you need a UNIQUE INDEX on term. So the query could be:Please note that $term and $date should be escaped to avoid SQL injections
What the above query does is to insert a new row in the table but if the term already exists (restricted by the UNIQUE INDEX) instead of inserting it will update the existing row incrementing the viewcount by 1.
Also note that UPDATES can lock your table up restricting future INSERTS and that could easily cause a deadlock on your database if your _searches table grows too big.