Shantanu's Blog
Database Consultant
October 21, 2009
Look for orphan pages
In order to check if there are no junk files in the datadir, simply run the following shell script. It will list all the files from a particular directory and search if that file is referred to from any file.
#!/bin/sh
> /home/develop/orphan1.txt
for myfile in `ls -R /var/www/html/ | tr "\t" "\n"`
do
grep -R -m1 $myfile /var/www/html/* > /dev/null 2>&1
if [[ $? -ne 0 ]];then
find /var/www/html/ -name $myfile >> /home/develop/orphan1.txt
fi
done
# sort remove duplicates and remove leading /var/www/html part of file path
# sort -u /home/develop/orphan1.txt | sed 's/^\/var\/www\/html//g' > /home/develop/orphan.txt
_____
In order to find if the tables are useless, simply check the table names in the mysql general log.
for mytable in `mysql -uroot -pPassWord test -BNe"show tables"`
do
mycount=`grep -c "$mytable" mysql-gen.log`
echo "$mytable" "$mycount" >> tableReport.txt
done
_____
You can also check if the table name is used anywhere in the code.
Table list was generated using the following command...
mysql -Bse"select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA='shantanu';" > /home/develop/tblist1.txt
The following shell script generated the table list...
# cat otable.sh
#!/bin/sh
> /home/develop/orphan1.txt
for myfile in `cat tblist1.txt | tr "\t" "\n"`
do
grep -R -m1 $myfile /var/www/html/* > /dev/null 2>&1
if [[ $? -ne 0 ]];then
echo "$myfile" >> /home/develop/orphan1.txt
fi
done
disclaimer: A table can be still useful even if it does not appear in the general log if it is a part of procedure, trigger or cron.
Labels: linux tips, mysql tips, shell script
October 18, 2009
PHP security tips
avoid SQL Injection
It can happen anywhere you have a form that the user can fill in and submit.
There is a PHP function to avoid the SQL Injection attack.
$query_ok = "SELECT * FROM users WHERE username = 'mysql_real_escape_string($injection_string)'";
Real escape strings will replace all single quote and double quote character with the escaped string \
$new_user=mysql_real_escape_string($_GET["injection_string"]);
$query_ok = "SELECT * FROM mysql.user WHERE User = '" . "$new_user" ."' limit 1";
echo $query_ok;
$result=mysql_query($query_ok) or die("some errror");
_____
If you need to use SMTP server to send mail, here is a nice writeup for the same.
http://9lessons.blogspot.com/2009/10/send-mail-using-smtp-and-php.html
Labels: php, php tips
Finding Database Name
In order to find out the database that is being used, you have exclude the other default DBs like mysql and test. Here is a simple shell script that will do the job.
#!/bin/sh
for dbName in `mysqlshow -uroot -pPassWord | awk '{print $2}'`
do
echo "$dbName" | egrep -v 'mysql|test|Databases|information_schema';
done
You can also echo it out on a single line like this...
echo $(mysqlshow -uroot -pPassWord | awk '{print $2}' | egrep -v 'mysql|test|Databases|information_schema|lost\+found')
Labels: mysql tips
October 15, 2009
throwing logs to bit bucket
If you need to turn the general log or slow query log on temporarily for debugging purposes, send it to /dev/null as shown below.
ln -fs /dev/null/ /var/log/mysql/general.log
then an ls -l would show
/var/log/mysql/mysql-general.log -> /dev/null
And to turn the query log on all you need to do is:
rm /var/log/mysql/mysql-general.log
and at the mysql command prompt:
mysql> FLUSH LOGS;
The same trick can be used for enabling / disabling apache error logs.
Labels: mysql tips
October 12, 2009
Installing standard procedures for MySQL
** Backup of Information Schema tables **
When the database has too many tables or when the innodb table space is too big, you can not run queries against information_Schema Database. It is a good idea to copy the data of those tables to a new database, for e.g. "schemaBackup". Here is the script that will do the needful.
# cat stats.sh
#!/bin/sh
mysql -e"create database if not exists schemaBackup";
for tblName in `mysql -e"show tables from information_schema"`
do
mysql -e"drop table if exists schemaBackup.$tblName;"
mysql -e"create table schemaBackup.$tblName select * from information_schema.$tblName;"
done
for tblName in `mysql -e"show tables from mysql"`
do
mysql -e"drop table if exists schemaBackup.$tblName;"
mysql -e"create table schemaBackup.$tblName select * from mysql.$tblName;"
done
_____
You can use the following line at command prompt to install all the required functions and stored procedures.
# lynx -source http://saraswaticlasses.net/yubnub/updates.txt | sed 's/information_schema/schemaBackup/g' | mysql -uroot -pPassWord mysql
If you are not using the backup Database, remove the "sed" clause.
Once the script is installed without any error, you can start calling the procedures and use the new functions.
// Show triggers
select * from mysql.SHOW_CREATE_TRIGGERS;
// create table customers with 5 columns in the test database
call mysql.createtable ('test.customers', 5);
// check if data violates foreign key constraint
call mysql.p_check_fk_constraint_violations('sakila','%');
// one liner to check foreign key violations
mysqlshow | egrep -v "(Databases|information_schema|performance_schema|mysql)" | awk '{print $2}' | sed '/^$/d' | awk '{sub($1,"mysql \-uroot \-Bse \"call mysql.p_check_fk_constraint_violations\('"'"'&'"'"','"'"'%'"'"'\)\""); print $0}' | sh
// check all DB's for data violation of foreign key
# for dbname in `mysqlshow`; do echo $dbname; mysql -e"call mysql.p_check_fk_constraint_violations('$dbname','%')"; done
// proper case
select mysql.proper('first character should be capital ');
// Normalize table with comma as delimiter
CALL mysql.normalize_table('myDB.myTable', 'uniquefield', 'ids', ',');
// list all columns
call mysql.getColumnNames('dbName', 'tableName');
// find reserved words used in DB
select a.table_schema, a.table_name, a.column_name from information_schema.columns as a inner join mysql.reserved_words as b on upper(a.column_name) = b.reserved_word;
select a.table_schema, a.table_name from information_schema.TABLES as a inner join mysql.reserved_words as b on upper(a.table_name) = b.reserved_word;
select a.table_schema from information_schema.TABLES as a inner join mysql.reserved_words as b on upper(a.table_schema) = b.reserved_word;
// list any object type for e.g. triggers from your database
select * from mysql.dba_objects where OBJECT_TYPE = 'trigger' and SCHEMA_NAME = 'dbName';
// list of redundant indexes (I_S_INDEXES: lists all indexes)
select * from mysql.I_S_REDUNDANT_INDEXES;
_____
// Add the following to bashrc so that you can simply type mysql_new to login fast.
vi ~/.bashrc
alias mysql_new='mysql -uroot -p --prompt="(\r:\m)\_mysql>" --show-warnings --tee="/home/sqltee.txt"'
alias myproxy="sh /usr/share/mysql/mysql-proxy-0.8.1-linux-rhel5-x86-64bit/bin/mysql-proxy --plugins=proxy --proxy-lua-script=/usr/share/mysql/mysql-proxy-0.8.1-linux-rhel5-x86-64bit/share/doc/mysql-proxy/failed-query.lua >> /home/failed_query.log &"
alias mysql_count='mysql -e"SELECT SUBSTRING_INDEX(host, \":\", 1) AS host_short, GROUP_CONCAT(DISTINCT USER) AS users, COUNT(*) as MYCOUNT FROM information_schema.processlist GROUP BY host_short with rollup;"'
vi ~/.bash_profile
script /home/shantanu/mylog_$(date '+%Y%m%d%H%M').log
screen -S shantanu
# to update the commands to the history
shopt -s histappend
PROMPT_COMMAND='history -a'
vi ~/.forward
shantanu.oa+forward@gmail.com
// Change the apache access log setting:
# cat /etc/httpd/conf/httpd.conf | grep LogFormat
#Old Format to be changed to the new format
#LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "\"%h\" \"%l\" \"%u\" \"%{%Y-%m-%d %H:%M:%S}t\" \"%r\" \"%>s\" \"%b\" \"%{Referer}i\" \"%{User-Agent}i\"" combined
Add the following scripts to /bin/ folder:
# cat /bin/wiki
#!/bin/sh
dig +short txt ${1}.wp.dg.cx
# cat /bin/mylog
#!/bin/sh
mysqlbinlog ${1} | grep -i -e "^update" -e "^insert" -e "^delete" -e "^replace" -e "^alter" | cut -c1-100 | tr '[A-Z]' '[a-z]' | sed -e "s/\t/ /g;s/\`//g;s/(.*$//;s/ set .*$//;s/ as .*$//" | sed -e "s/ where .*$//" | sort | uniq -c | sort -nr
mysqlbinlog ${1} | grep -i ^use | sort -u
# cat /bin/findtable
#!/bin/sh
mysql -e"select TABLE_SCHEMA, TABLE_NAME, ENGINE, TABLE_ROWS, CREATE_TIME FROM information_schema.TABLES where TABLE_NAME LIKE '%$1%';"
# cat /bin/mydisk
#!/bin/sh
mysize=${1:-1000}
find / -type f -size +"$mysize"M -exec ls -lh {} \; | awk '{ print $9 ": " $5 }'
# cat /bin/mydiff
#!/bin/sh
for i in {1..10}
do
mysql -e"SELECT STRAIGHT_JOIN
LOWER(gs0.VARIABLE_NAME) AS variable_name,
gs0.VARIABLE_VALUE AS variable_value_0,
gs1.VARIABLE_VALUE AS variable_value_1,
(gs1.VARIABLE_VALUE - gs0.VARIABLE_VALUE) AS variable_value_diff,
(gs1.VARIABLE_VALUE - gs0.VARIABLE_VALUE) / 10 AS variable_value_psec,
(gs1.VARIABLE_VALUE - gs0.VARIABLE_VALUE) * 60 / 10 AS
variable_value_pminute
FROM
(
SELECT
VARIABLE_NAME,
VARIABLE_VALUE
FROM
INFORMATION_SCHEMA.GLOBAL_STATUS
UNION ALL
SELECT
'',
SLEEP(30)
FROM DUAL
) AS gs0
JOIN INFORMATION_SCHEMA.GLOBAL_STATUS gs1 USING (VARIABLE_NAME)
WHERE
gs1.VARIABLE_VALUE != gs0.VARIABLE_VALUE
;"
done
# cat /bin/mycheck
#!/bin/sh
master=$(mysql -e"show slave status\G" | grep "Master_Host" | awk -F":" '{print $2}')
second_master=$(mysqladmin processlist | grep 'Binlog' | awk -F"|" '{print $4}' | awk -F":" '{print $1}')
remote_server=${1:-$master}
remote_server=${remote_server:-$second_master}
user_name=${2:-root}
user_password=${3:-root@123}
echo "Comparing localhost with remote server at $remote_server using $user_name and $user_password"
echo `date`
for dbName in `mysqlshow`
do
/usr/bin/mk-table-checksum h=localhost,P=3306 --databases $dbName h=${remote_server},u=$user_name,p=$user_password,P=3306 --databases $dbName --count --no-crc | /usr/bin/mk-checksum-filter
done
// add MAILTO=shantanu.oa@gmail.com to crontab
// Check if tuning-primer.sh is installed
// make sure maatkit is installed
// install adminer.php to manage the mysql database
wget -directory-prefix=/var/www/html/ -O adminer.php http://downloads.sourceforge.net/project/adminer/Adminer/Adminer%202.0.0/adminer-2.0.0-en.php
_____
cat /bin/multi
#!/bin/sh
# chmod 755 /bin/multi
# to start or stop multiple instances of mysql
# multi start
# multi stop
# change the root user and password # default action is to start
action=${1:-"start"}
stop()
(
for socket in {2..9}
do
mysqladmin shutdown -uroot -proot@123 --socket=/tmp/mysql.sock$socket
done
)
start()
(
for socket in {2..9}
do
mysqld_multi start $socket
done
)
$action
_____
Here are a few important crons :
# Check differences, use the table-sync utility to check the differences
# /usr/bin/mk-table-sync --print
55 22 * * * (/usr/bin/mk-table-checksum h=10.10.10.10,u=root,p=root@123,P=3306 --databases test h=11.11.11.11,u=root,p=root@123,P=3306 --databases test | /usr/bin/mk-checksum-filter) | sed "s/^/$(date '+\%Y\%m\%d\%H\%M') /g" >> /home/shantanu/mk_check_sed.txt 2>> /home/shantanu/mk_check_sed_err.txt
# 54 23 * * * diff <(mysqldump -h11.11.11.11 -uroot -proot@123 test myinfo --skip-extended-insert) <(mysqldump -h10.10.10.10 -uroot -proot@123 test myinfo --skip-extended-insert) --side-by-side --suppress-common-lines --width=690 | more
52 06 * * * grep nagios /var/log/messages | grep "`date '+\%b \%e'`" | mail -s"nagios log of `hostname`" monitor+`hostname`@wavecrest.gi > /home/shantanu/nagios_success.txt 2> /home/shantanu/nagios_err.txt
## log alerts to /var/log/messages
# mysql high processes
*/5 * * * * myvar1=$(mysqladmin -h11.11.11.11 -uroot -proot@123 processlist | wc -l | awk '{print int($1)}'); [ $myvar1 -gt 80 ] && logger "MySQL processes on 101 are high $myvar1 at $(date)" >/dev/null 2>&1
*/5 * * * * myvar1=$(mysqladmin -h10.10.10.10 -uroot -proot@123 processlist | wc -l | awk '{print int($1)}'); [ $myvar1 -gt 80 ] && logger "MySQL processes on 102 are high $myvar1 at $(date)" >/dev/null 2>&1
# kill query running too long
#* * * * * /usr/bin/mk-kill --print --daemonize --interval 5 --busy-time 2000 --ignore-info '(?i-smx:^insert|^update|^delete)' --match-info '(?i-xsm:select)' --log /var/log/mk-kill.log --execute-command '(echo "Subject: mk-kill query found on `hostname`"; tail -1 /var/log/mk-kill.log) | mail -s "mk-kill on `hostname`" monitor+`wavecrest`@wavecrest.gi' --kill-query >> /home/shantanu/kill_success.txt 2>> /home/shantanu/kill_err.txt
_____
ps helper
A new database ps_helper is created and useful functions like
format_bytes, format_time are installed along with diasnostic table
views based on performance_schema.
curl http://www.markleith.co.uk/wp-content/uploads/2012/07/ps_helper_55.sql_.txt | mysql
This is 5.5 version. Change the filename to 56.sql in order to install on 5.6 version.
_____
// remove myisam tables from a schema UpORS
mysql information_schema -Bse"select concat('drop table ', TABLE_NAME, ';') from TABLES WHERE TABLE_SCHEMA = 'UpORS' and ENGINE = 'MyISAM'" | mysql UpORS
// remove innodb tables without any foreign key refernce from schema UpORS
mysql information_schema -Bse"select concat('drop table ', a.TABLE_NAME, ';') from TABLES AS a left join
(select TABLE_NAME from TABLE_CONSTRAINTS where CONSTRAINT_SCHEMA = 'UpORS' GROUP BY TABLE_NAME) as b
on a.TABLE_NAME = b.TABLE_NAME
WHERE a.TABLE_SCHEMA = 'UpORS' and b.TABLE_NAME IS NULL" | mysql UpORS
Labels: mysql tips, shell script
October 09, 2009
Naming my baby
Append the variable name with the variable type. for e.g. instead of just saying FirstName you can call it strFirstName like this...
$strFirstName = ’sonny’;
$intAge = 5;
There are 2 types of Case styles:
Pascal Case -> ThisIsPascalCase (Also Called Upper Camel Case)
Camel Case -> thisIsCamelCase (Also Called Lower Camel Case)
_____
Zend Framework has defined the following guidelines for naming variables and function names.
Classes – PascalCase (UpperCamelCase)
Class names must match the name of the directory on the file system that contains the class file. If you have a class file named Car.php in the path ‘/Models/Car.php’ then the class name would have to be Models_Car.
Functions and Methods – camelCase
Names must describe behavior of function or method.
Methods that are declared with private or protected visibility modifier must start with an _.
Constants – ALL_CAPS
Labels: php
Pear Problem
Some PEAR installations on PHP 5.2.9 and 5.2.10 seem to be corrupted. When trying to install something, you will get the error:
pear.php.net is using a unsupported protocal – This should never happen. install failed
This problem comes from corrupted channel files. Go into your PEAR php directory and backup .channels directory:
cd `pear config-get php_dir`
mv .channels .channels-broken
pear update-channels
This means you lost all your channels except for the default ones (pear, pecl, doc and __uri) – but at least you do not have to re-install PEAR.
Labels: pear
PHP memory management
Do not forget to delete the data stored in the buffer.
$long_result = mysql_query('SELECT * FROM `posts`');
//Output $long_result
unset($long_result);
$var = 'Lorem ipsum dolor sit amet. Lorem ipsum dolor sit.';
echo $var;
unset($var);
?>
Labels: php
php.ini file setting
There are many people who talk about my.cnf setting for mysql. But I do hardly hear anything about php.ini setting. Here are a few tips...
asp_tags = Off
display_errors = On
display_startup_errors = Off
log_errors = Off
safe_mode = Off
register_globals = Off
short_open_tag = Off
sql.safe_mode = Off
max_input_time = 60
magic_quotes_gpc = Off
track_errors = Off
Labels: php
Show create trigger
MySQL 5.0 lacks "SHOW CREATE TRIGGER". Here's a VIEW to list all triggers and (a close approximation of) their CREATE statements.
CREATE VIEW `SHOW_CREATE_TRIGGERS` AS
SELECT
TRIGGER_NAME AS 'trigger_name'
,CONCAT_WS(
" ",
"DELIMITER $$\nCREATE TRIGGER",
TRIGGER_NAME,
ACTION_TIMING,
EVENT_MANIPULATION,
"ON",
EVENT_OBJECT_TABLE,
"FOR EACH ROW",
ACTION_STATEMENT,
"$$\nDELIMITER ;"
) AS 'sql'
FROM information_schema.triggers;
Labels: mysql tips
October 08, 2009
Pager to compare resultset
While optimizing a query, one might need to know if the query will return the exact same results as the last query. We can use the combination of pager and md5 checksum for the purpose.
mysql> pager md5sum
mysql> select * from City as c, Country ct where c.countrycode = ct.code;
3c8c6b8331c9270f8565edd1a8b8d7a5 -
4079 rows in set (0.05 sec)
mysql> select * from City c join Country ct ON(c.countrycode = ct.code);
3c8c6b8331c9270f8565edd1a8b8d7a5 -
4079 rows in set (0.05 sec)
mysql> nopager
Or just log out and log back in.
Labels: mysql tips
Mysql prompt and tee
You can change the MySQL prompt as well as start saving the output to a text file.
mysql -uroot -p --prompt="(\r:\m)\_mysql>" --show-warnings --tee="/home/sqltee.txt"
You can also create an alias and add the command to the .bashrc file that can be found in the home directory.
vi ~/.bashrc
alias mysql_new='mysql -uroot -p --prompt="(\r:\m)\_mysql>" --show-warnings --tee="/home/sqltee.txt"'
Labels: mysql tips
Archives
June 2001
July 2001
January 2003
May 2003
September 2003
October 2003
December 2003
January 2004
February 2004
March 2004
April 2004
May 2004
June 2004
July 2004
August 2004
September 2004
October 2004
November 2004
December 2004
January 2005
February 2005
March 2005
April 2005
May 2005
June 2005
July 2005
August 2005
September 2005
October 2005
November 2005
December 2005
January 2006
February 2006
March 2006
April 2006
May 2006
June 2006
July 2006
August 2006
September 2006
October 2006
November 2006
December 2006
January 2007
February 2007
March 2007
April 2007
June 2007
July 2007
August 2007
September 2007
October 2007
November 2007
December 2007
January 2008
February 2008
March 2008
April 2008
July 2008
August 2008
September 2008
October 2008
November 2008
December 2008
January 2009
February 2009
March 2009
April 2009
May 2009
June 2009
July 2009
August 2009
September 2009
October 2009
November 2009
December 2009
January 2010
February 2010
March 2010
April 2010
May 2010
June 2010
July 2010
August 2010
September 2010
October 2010
November 2010
December 2010
January 2011
February 2011
March 2011
April 2011
May 2011
June 2011
July 2011
August 2011
September 2011
October 2011
November 2011
December 2011
January 2012
February 2012
March 2012
April 2012
May 2012
June 2012
July 2012
August 2012
October 2012
November 2012
December 2012
January 2013
February 2013
March 2013
April 2013
May 2013
June 2013
July 2013
September 2013
October 2013
January 2014
March 2014
April 2014
May 2014
July 2014
August 2014
September 2014
October 2014
November 2014
December 2014
January 2015
February 2015
March 2015
April 2015
May 2015
June 2015
July 2015
August 2015
September 2015
January 2016
February 2016
March 2016
April 2016
May 2016
June 2016
July 2016
August 2016
September 2016
October 2016
November 2016
December 2016
January 2017
February 2017
April 2017
May 2017
June 2017
July 2017
August 2017
September 2017
October 2017
November 2017
December 2017
February 2018
March 2018
April 2018
May 2018
June 2018
July 2018
August 2018
September 2018
October 2018
November 2018
December 2018
January 2019
February 2019
March 2019
April 2019
May 2019
July 2019
August 2019
September 2019
October 2019
November 2019
December 2019
January 2020
February 2020
March 2020
April 2020
May 2020
July 2020
August 2020
September 2020
October 2020
December 2020
January 2021
April 2021
May 2021
July 2021
September 2021
March 2022
October 2022
November 2022
March 2023
April 2023
July 2023
September 2023
October 2023
November 2023
April 2024
May 2024
June 2024
August 2024
September 2024
October 2024