Archive for the “mySQL” Category

So I thought maybe it’s time for an update.

The project is moving, albeit slowly, and I realy do not like the current PHP implementation, I want to move towards a C++ version, and I will do so as soon as I figure out how to do CLI “update/refresh” …

i.e. See how W GET works with the progress bar and kbps all in text, I have NO idea how that works.

I am also looking at adding RRDTOOL support.

Anyway here’s the current sample output:

1
[buzz@server01 .sysadmin]$ ./dbstat.php summary

1
----- mySQL dbStat v1.1 Summary Report-----

1
10 Databases checked

1
exampledb1: 13 tables (0 VIEWS 13 INNODB 0 MYISAM) 0.77MB DATA 0.64MB INDEX

1
exampledb2: 15 tables (0 VIEWS 14 INNODB 1 MYISAM) 0.22MB DATA 0.19MB INDEX

1
exampledb3: 62 tables (0 VIEWS 0 INNODB 62 MYISAM) 0.45MB DATA 0.5MB INDEX

1
exampledb4: 3 tables (0 VIEWS 0 INNODB 3 MYISAM) 0.02MB DATA 0.01MB INDEX

1
exampledb5: 4 tables (0 VIEWS 0 INNODB 4 MYISAM) 0.02MB DATA 0.01MB INDEX

1
exampledb6: 4 tables (0 VIEWS 0 INNODB 4 MYISAM) 39.81MB DATA 22.22MB INDEX

1
exampledb7: 3 tables (0 VIEWS 0 INNODB 3 MYISAM) 0.04MB DATA 0.01MB INDEX

1
exampledb9: 599 tables (8 VIEWS 1 INNODB 590 MYISAM) 8702.79MB DATA 4559.42MB INDEX

1
exampledb10: 22 tables (0 VIEWS 21 INNODB 1 MYISAM) 6.66MB DATA 2.26MB INDEX

Detail:

1
----- START mySQL dbStat v1.1 Detail Report: exampledb9 -----
1
exampledb9: 599 tables (8 VIEWS 1 INNODB 590 MYISAM) 8893.7MB DATA 4583.54MB INDEX
1
--- Table Index Ratio Report index:data (457 Tables) ---
1
exampledb9.table1: 315.0769:1
1
exampledb9.table2: 315.0769:1
1
exampledb9.table3: 157.5385:1
1
exampledb9.table4: 146.2857:1
1
exampledb9.table5: 128.0000:1

… (I’ve truncated this very long list)

1
--- Table Fragmentation Report (2 Tables) ---
1
exampledb9.atable: 0.6067
1
exampledb9.atable: 0.1285
1
--- Table Low Size Report (47 Tables) ---
1
exampledb9.atable: 0 bytes
1
exampledb9.atable: 0 bytes
1
exampledb9.atable: 0 bytes
1
exampledb9.atable: 0 bytes
1
exampledb9.atable: 0 bytes

… (Truncated again)

1
--- Table Detail Report (591 Tables) ---
1
SCHEMA.TABLENAME: ENGINE: ROWS: TOTAL SIZE (MB): DATA SIZE (MB): DATA PERCENTAGE OF TOTAL (%): INDEX SIZE (MB): INDEX PERCENTAGE OF TOTAL (%): LAST UPDATE TIME
1
exampledb9.a_table: MyISAM: 28906414: 3272.43531003: 3031.82567548: 92.6474: 204.63809450: 7.3526: 2008-05-22 11:59:42

.. (truncated)

1
----- END mySQL dbStat v1.1 Detail Report: exampledb9 -----

Tags: , ,

Comments No Comments »

Seems that dbStat had to be developed much faster than I realised, it _was_ a personal project that I was working on as I got time.

Now it has been completely re-written to provide a complete “break down” of a large mySQL database suffering some major iowait (on average 15%).

The database in question was 17GB in size with 63% of that data size being pure indexes … MAJOR headache.

After completion of v1.0 dbStat, and subsequent review of the output, we were able to reduce the Index size by 7GB (41% of Total).

So the datbase is siting at ~10gb (40% index), plenty more work to do, but by removing the problem causing indexes we have reduced the index overhead and stemmed a growth of ~380mb/24hrs

Rapid development has left a few bugs, currently dbStat is at v1.2 with a very buggy CSV export function, anyway more as the project progresses, it also raises a few questions about public release now due to it being laregly to resolve a business issue.

Hmm maybe I can get a testimonial! haha

EDIT: iowait is down to 2.28% now :D

Comments No Comments »

Trent Hornibrook has started a mysql dba blog, so I thought i’d provide some linkage :-)

These two articles cover how to use the mysql explain syntax for “debugging” sql queries so be sure to read part 1 and part 2

Tags: , ,

Comments No Comments »

Due to latency issues, and the lack of multi site support I have ditched my old web-host.

 In favour of an all singing all dancing NEW ONE! nativespace thus-far I have had excellent ticket turn around (all in 30 mins or less), and my initial sales enquiry (consisting of a lot of lengthy questions)  responded to in …. 6 minutes!

So thus far definitely on my recommended list

Tags:

Comments 1 Comment »

To often I get passed code to review that quite frankly is so full of holes it wouldn’t make an adequate sieve…

So in this quick blog I outline a few simple and easily implemented steps to ensure as you start out in the world of PHP, your first site isn’t hacked within 5 minutes, leaving you a whimpering wrek …

PHP DON’T EXAMPLE 1:

Passing RAW globals to mysql!

i.e.

1
2
$sql = "SELECT * FROM users WHERE email='.$_GET['email']."' and password='".$_GET['password']"';";
$result = mysql_query($sql);

So what is wrong with the above? SQL INJECTION welcome to a world where people want to break your website, simply because they can …

I am not going to add more description, just click through to the wiki pedia entry linked above …

To avoid this PHP comes with two functions mysql_escape_string() and mysql_real_escape_string()

An example taken from the mysql_real_escape_string() page:

Example#2 An example SQL Injection Attack

1
2
3
4
<span style="color: #000000;"><span style="color: #0000bb;">&lt;?php
</span><span style="color: #ff8000;">// Query database to check if there are any matching users
</span><span style="color: #0000bb;">$query </span><span style="color: #007700;">= </span><span style="color: #dd0000;">"SELECT * FROM users WHERE user='{$_POST['username']}' AND password='{$_POST['password']}'"</span><span style="color: #007700;">;
</span><span style="color: #0000bb;">mysql_query</span><span style="color: #007700;">(</span><span style="color: #0000bb;">$query</span><span style="color: #007700;">);</span></span>
1
2
3
4
5
<span style="color: #000000;"><span style="color: #007700;"> </span><span style="color: #ff8000;">// We didn't check $_POST['password'], it could be anything the user wanted! For example:
</span><span style="color: #0000bb;">$_POST</span><span style="color: #007700;">[</span><span style="color: #dd0000;">'username'</span><span style="color: #007700;">] = </span><span style="color: #dd0000;">'aidan'</span><span style="color: #007700;">;
</span><span style="color: #0000bb;">$_POST</span><span style="color: #007700;">[</span><span style="color: #dd0000;">'password'</span><span style="color: #007700;">] = </span><span style="color: #dd0000;">"' OR ''='"</span><span style="color: #007700;">;</span></span><span style="color: #007700;"><span style="color: #ff8000;">// This means the query sent to MySQL would be:
</span><span style="color: #007700;">echo </span><span style="color: #0000bb;">$query</span><span style="color: #007700;">;
</span><span style="color: #0000bb;">?&gt;</span></span>

The query sent to MySQL:

1
<code>SELECT * FROM users WHERE user='aidan' AND password='' OR ''=''

This would allow anyone to log in without a valid password.

So in summary READ the mysql_real_escape_string() page, and even if you don't implement the "best practice" example on that page PLEASE make sure you at least escape $_SESSION $_GET $_POST inputs with a mysql escape function!

Tags: , , ,

Comments 3 Comments »

So you’ve recently made a change to your mysql installation and see the following in

 /var/lib/mysql/server.err

 

1
2
080317 14:08:50 mysqld started
080317 14:08:50 [ERROR] Fatal error: Can't change to run as user 'mysql' ; Please check that the user exists!
1
2
3
4
5
080317 14:08:50 [ERROR] Aborting

080317 14:08:50 [Note] /usr/sbin/mysqld: Shutdown complete

080317 14:08:50 mysqld ended

 This is a problem that many a time spent on google has not found the result, so I am writing here what exactly to do in this situation …

 First off

1
 cd /var/lib/mysql

Now run

1
ls -la

 No doubt you will see something similar to this:

1
drwx--x--x   2 27 mysql     4096 Mar 17 14:05 mysql

Notice the “27 mysql”, the user no longer existsing in /etc/passwd.

This is fairly simple to fix.

1
adduser mysql
1
chown mysql:mysql -R /var/lib/mysql

Now start up Mysql i.e. “service start mysql” and everyhing _should_ be fine. 

Tags:

Comments No Comments »

I have been working on a script as of late to aid in the ever ongoing process of optimizing a web applications “back end”, inevitably the database, and underlying code.

Thus dbstat was born, the current version is not for release _just yet_ , as some tweaks are still needed, at the moment it only supports reporting for a single database at any one time.

v 0.5 Features list.

  1. Dynamic / Fixed row size checking. (Dynamic size rows can cause table fragmentation).
  2. MyISAM / InnoDB  checking (Reports total number of tables using these engines).
  3. Index threshold testing.
  4. Table fragmentation threshold testing.
  5. Table size threshold testing.
  6. Database size reporting.

At the moment this is currently written in PHP, and is quite heavily scripted I will be looking to move to C++ for a v1.0 for the release, for calculations sake and to remove the need to install PHP.

I will post more information as the project develops, I will be looking to release the program and source under GPL by version 1.

By version 1, I intend to have included the following:

  1. User interactive reporting. (On even of threshold being exceeded, prompt user to fix or skip, with cursory notes*)
  2. Table de-fragmentation.
  3. Reporting to include suggested fixes.

*Cursory notes  to describe the fix, and possible implications of actioning it.

So watch this space, and please leave requests via comments :)

Tags: , , , ,

Comments 1 Comment »

** Note I am not the “Buzz” from 3dbuzz.com this is just a coincidence **

All right lets begin…

First off you will need to understand how to take advantage of mySQL’s inbuilt fulltext search functionality.

First lets create the table, using the cli or your favorite GUI (i.e. mysql administrator) to run the following SQL statement.

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CREATE DATABASE sion_ft;

USE sion_ft;

CREATE TABLE sion_ft_tutorial (

Id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,

Title VARCHAR (255),

Body LONGTEXT

)

ENGINE=myISAM;

ALTER TABLE sion_ft_tutorial ADD FULLTEXT SEARCH (title,body);

Ok we have now created a database, changed to use that database, and created that databases first table, then altered the table to add a fulltext index for both the title and body columns, and called this index “search”.

Notice the “ENGINE=myISAM;”, unfortunately it seems InnoDB does not support full text indexes. At least that’s the problem I ran into using mySQL 4.x.

Now before we go any further we need to put some data into that database so it can be searched.

Code:

1
2
3
4
5
6
7
8
9
10
11
INSERT INTO sion_ft_tutorial (title,body) VALUES

('Sion Fulltext tutorial at 3dbuzz', 'Posted originally by sion at the 3dbuzz forums'),

('3DBUZZ.com ', 'Look Listen Learn, forums vtm\'s and more'),

('I am hungry', 'Lets order pizza!!' ),

('hi Ho Hi Ho', 'A forum trolling I will go' ),

('PHP problems?', 'Go to 3dbuzz forums, where some nutter called sion roams.' );

Ok now we have inserted 5 rows of data into the table, we will use this data when testing our fulltext search.

Before we begin with the PHP we need to construct the SQL statement to use the FULL text feature, so keep that CLI OPEN!

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
SELECT * FROM sion_ft_tutorial WHERE MATCH(title,body) AGAINST('sion');

+----+----------------------------------+----------------------------------------------------------+

| id | title | body |

+----+----------------------------------+----------------------------------------------------------+

| 1 | Sion Fulltext tutorial at 3dbuzz | Posted originally BY sion at the 3dbuzz forum… |

| 5 | PHP problems? | GO TO 3dbuzz forum, WHERE SOME nutter called sion roams. |

+----+----------------------------------+----------------------------------------------------------+

Ok so the search is now working no we need to get the relevance score working.

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
SELECT *, MATCH(title,body) AGAINST('sion') AS score FROM sion_ft_tutorial WHERE MATCH(title,body) AGAINST('sion');

+----+----------------------------------+----------------------------------------------------------+------------------+

| id | title | body | score |

+----+----------------------------------+----------------------------------------------------------+------------------+

| 1 | Sion Fulltext tutorial at 3dbuzz | Posted originally BY sion at the 3dbuzz forum… | 0.53033631317832 |

| 5 | PHP problems? | GO TO 3dbuzz forum, WHERE SOME nutter called sion roams. | 0.37130504609119 |

+----+----------------------------------+----------------------------------------------------------+------------------+

As you can see id 1 has the higher score this is because “sion” is found both in the title and the body text.

The “relevance score” is calculated by hard code formulae within mySQL.

Full details on this formulae can be found here : http://dev.mysql.com/doc/internals/en/full-text-search.html

This covers the mySQL side of the system.

PHP

First off we have to make some assumptions for this method to work.

We have to assume that the highest score is equivalent to 100% relevant to the search.

And for this “basic” stage we have to assume that the default mySQL setup is sufficient for our needs, as there is a whole host of things to configure such as minimum word length, and mySQL’s “stop list” to consider.

This will be covered in the “fine tuning” section of this tutorial.

I am also assuming you have read the above section on mySQL and not skipped strait to the PHP code.

First of all as I’m sure you know we need to create a connection to the mySQL server.

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?PHP

$usr = "mysqlusr";

$pass = "mysqlpass";

$host = "localhost";

$db = "sion_ft";

$connection = mysql_connect($host,$usr,$pass);

mysql_select_db($db,$connection);

?>

Ok so lets now get some data to start playing with.

Code:

1
2
3
4
5
6
7
8
9
<?PHP

$query = "SELECT *, MATCH(title,body) AGAINST('sion') AS score FROM sion_ft_tutorial WHERE MATCH(title,body) AGAINST('sion') ORDER BY SCORE DESC";

$result = mysql_query($query);

$row = mysql_fetch_assoc($result);

??

Now we have the data as mentioned above in the MYSQL section.

Remember I said we have to “assume” the highest score is 100% relevant. well lets do that and start creating relevance percentages.

Code:

1
2
3
4
5
6
7
8
9
10
11
$max_score = 0;

$data = array();

do {

if($row['score'] &gt; $max_score){ $max_score = $row['score']; } //because we are ordering by score we can assume on the first run this wil be the max score.

echo $row['title']." ".@number_format(($row['score']/$max_score)*100,0)."%&lt;br&gt;n";

}while($row = mysql_fetch_assoc($result));

Now you should get a list that looks something like the following.

1
2
3
Sion Fulltext tutorial at 3dbuzz 100%

PHP Problems? 70%

Right so lets go over what we have done so far, we have used mySQL’s inbuilt “relevance” calculation and assume the highest “score” to bee 100% as such we have used that score as the “denominator” for the result of the results to calculate their percentage relevance.

Tags: , , ,

Comments No Comments »