How can I speed up a MySQL product search result? - php

I am doing a query on an mysql database based on typed data sent from a jquery autocomplete function. It works fine but take several seconds (5-6+) to get the returned suggestions. There are around 200,000 product entries in the database currently which is expected to go to well over a million entries. How can I speed this thing up, as once more entries are added, it stands to reason that the results would likely never show before someone has already typed in the full search query, which does not benefit them at all.
The MySQL tables are:
CREATE TABLE `products` (
`id` int(12) NOT NULL auto_increment,
`name` varchar(255) NOT NULL default '',
`description` text NOT NULL,
`category` int(12) NOT NULL default '0',
PRIMARY KEY (`id`),
KEY `name` (`name`),
KEY `category` (`category`)
) ENGINE=MyISAM;
CREATE TABLE `products_pics` (
`id` int(12) NOT NULL auto_increment,
`product_id` int(12) NOT NULL default '0',
`thumb` blob NOT NULL,
`image` longblob NOT NULL,
`type` varchar(6) NOT NULL default '',
PRIMARY KEY (`id`),
KEY `product_id` (`product_id`),
) ENGINE=MyISAM;
The PHP code for the search and result return is:
if(isset($_REQUEST['queryString'])) {
$queryString = addslashes($_REQUEST['queryString']);
if(strlen($queryString) > 0) {
$result = mysql_query("SELECT * FROM products WHERE name LIKE '%" . $queryString . "%' ORDER BY name LIMIT 8", $db);
if(mysql_num_rows($result) > 0){
while($myrow = mysql_fetch_array($result)){
$query = mysql_query("SELECT id FROM products_pics WHERE product_id='$myrow[id]' LIMIT 1", $db);
if(mysql_num_rows($query) > 0){
echo '<a href=""><img src="/ajax/search_images.php?id=' . $myrow[id] . '" width="55" border="0" alt="" />';
}
else {
echo '<a href=""><img src="/images/items/no-img.jpg" width="55" border="0" alt="" />';
}
$name = stripslashes($myrow[name]);
if(strlen($name) > 35) {
$name = substr($name, 0, 35) . "...";
}
echo '<span class="searchheading">' . $name . '</span>';
$description = stripslashes($myrow[description]);
if(strlen($description) > 80) {
$description = substr($description, 0, 80) . "...";
}
echo '<span>' . $description . '</span></a>';
}
echo '<span class="seperator"></span>';
}
}
}
Thanks again guys, any help is appreciated.

Doing LIKE %keyword% is very slow. Because you are doing autocomplete you could discard the first %, doing: LIKE keyword%.
That will speed up your query dramatically.
Also, try to execute your query in MYSQL like 'EXPLAIN <>'. This will provide you with info on how MySQL executes your query and where you might optimize.
Another option might be to use MyISAM's FULL TEXT SEARCH capability: http://dev.mysql.com/doc/refman/5.1/en/fulltext-search.html

Related

How to simplify (loop) if else statement and get mysql table column's name (PHP) [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I need help,
Scenario: Hotel, Checking Guests In. data in MySQL database.
MySQL:
CREATE TABLE IF NOT EXISTS `hotels` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Name` varchar(50) NOT NULL,
`Date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`Room01` int(11) NOT NULL,
`Room02` int(11) NOT NULL,
`Room03` int(11) NOT NULL,
`Room04` int(11) NOT NULL,
`Room05` int(11) NOT NULL,
`Room06` int(11) NOT NULL,
`Room07` int(11) NOT NULL,
`Room08` int(11) NOT NULL,
`Room09` int(11) NOT NULL,
`Room10` int(11) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
$result = mysql_query("SELECT * FROM hotels WHERE Name = 'hotel1'");
$row = mysql_fetch_array($result);
$room01 = $row['room01'];
0 = empty, 1 = not empty.
here is my code:
<?php
//example
$room01=1;
$room02=1;
$room03=0;
$room04=0;
//example
if ($room01 == 0)
{
echo "Your room is room01.";
}
elseif ($room02 == 0)
{
echo "Your room is room02.";
}
elseif ($room03 == 0)
{
echo "Your room is room03.";
}
elseif ($room04 == 0)
{
echo "Your room is room04.";
}
else
{
echo "None!";
}
?>
Result: Your room is room03.
What if I have 100 Rooms?
How to simplify if else statement and get the room name?
Use array_filter to find all empty rooms from database result and then print first room name, if any. Here's how you can write code without assuming there are 100 or n number of rooms in your database.
const EMPTY_ROOM = 0;
const OCCUPIED_ROOM = 1;
$rows = mysql_fetch_array($result);
$emptyRooms = array_filter($rows, function($room_value) {
return EMPTY_ROOM === $room_value;
});
if(empty($emptyRooms) || !is_array($emptyRooms)) {
echo 'None!';
return;
}
$rooms = array_keys($emptyRooms);
echo 'Your room is ' . $rooms[0] . '.' . PHP_EOL;
Update: It's probably because strict check is failing (EMPTY === $room_value). When you get data from database $room_value holds string data. Here's updated code:
function readDatabase() {
$handle = mysql_connect('localhost', 'root');
mysql_select_db('stackexchange');
if(!$handle) {
exit(mysql_error($handle));
}
$result = mysql_query("SELECT * FROM hotels WHERE Name = 'hotel1'", $handle);
return mysql_fetch_array($result, MYSQL_ASSOC);
}
$row = readDatabase();
const EMPTY_ROOM = '0';//set to string value to compare against database value
//use `array_slice` to get rid of columns: `id`, `Name`, `Date`.
//We want to search only in remaining columns: Room01, Room02 .... RoomN.
$row = array_slice($row, 3);
$emptyRooms = array_filter($row, function($room_value) {
return EMPTY_ROOM === $room_value;
});
if(empty($emptyRooms) || !is_array($emptyRooms)) {
echo 'None!';
return;
}
$rooms = array_keys($emptyRooms);
echo 'Your room is ' . $rooms[0] . '.' . PHP_EOL;
This should work (small explanation inside):
$row = mysql_fetch_array($result);
$roomNumber = 1;
//Get data from array
foreach($row as $data){
//if room returns 0 (empty)
if($data == 0){
if($roomNumber < 10){
echo "Your room is room0". $roomNumber;
break;
} else {
echo "Your room is room". $roomNumber;
break;
}
} else {
$roomNumber++;
}
}
The benefit of this approach is that it doesn't matter how many rooms you have. You can add or remove as many as you like. It'll loop through all of them, without having to adept the code.
EDIT:
After #Strawberrys comment, I realise that although my answer will work, this is not the way you should continue. Database normalisation would be the way to go. For example:
CREATE TABLE `hotels` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`Name` VARCHAR(64) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
CREATE TABLE `rooms` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`Hotel_id` INT(11) NOT NULL,
`Date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`Room_number` INT(5) NOT NULL,
`Occupied` INT(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
Using this type of Database design, you can easily add and remove Hotels to your system. Using Hotel_id as a reference, you can now easily add and remove rooms to your Hotels, without having to use an insane amount of table columns.
To use it, you simply query the Hotel_id inside rooms to get all rooms returned. Afterwards it's just a matter of checking the first Room_number where Occupied returned 0.
use array_search
const EMPTY_ROOM = 0;
$roomNumber = array_search(EMPTY_ROOM, $row);
if(false === $roomNumber) {
echo 'None!';
return;
}
echo 'Your room is ' . $roomNumber . '.' . PHP_EOL;
Update
hmm, I used test data to generate input. With your table structure here's updated code:
function readDatabase() {
$handle = mysql_connect('localhost', 'root');
mysql_select_db('stackexchange');
if(!$handle) {
exit(mysql_error($handle));
}
$result = mysql_query("SELECT * FROM hotels WHERE Name = 'hotel1'", $handle);
return mysql_fetch_array($result, MYSQL_ASSOC);
}
const EMPTY_ROOM = 0;
const OCCUPIED_ROOM = 1;
$row = readDatabase();
//use `array_slice` to get rid of columns: `id`, `Name`, `Date`. We want to search only in remaining columns: Room01, Room02 .... RoomN.
$roomNumber = array_search(EMPTY_ROOM, array_slice($row, 3));
if(false === $roomNumber) {
echo 'None!';
return;
}
echo 'Your room is ' . $roomNumber . '.' . PHP_EOL;

Create a new page on submit from database

I've created a chained menu using php and a database, following this tutorial.
The first table content a list of categories like :
CREATE TABLE IF NOT EXISTS `chainmenu_categories` (
`id_cat` int(4) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(40) NOT NULL,
PRIMARY KEY (`id_cat`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=12 ;
My second table, the type, like :
CREATE TABLE IF NOT EXISTS `type` (
`id_type` int(4) unsigned NOT NULL AUTO_INCREMENT,
`id_cat` int(4) unsigned NOT NULL,
`name` varchar(40) NOT NULL,
`destination` varchar(40) NOT NULL,
PRIMARY KEY (`id_type`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=7 ;
I managed, once clicking on submit, to redirect to another page by that in my select.php:
var result = $("select#type option:selected").html();
$("#select_form").submit(function( event ) {
var the_url = $("#type").val();
window.location = the_url;
event.preventDefault();
});
and adding this on my select.class.php
public function ShowCategory()
{
$sql = "SELECT * FROM chainmenu_categories";
$res = mysql_query($sql,$this->conn);
$category = '<option value="0">choose...</option>';
while($row = mysql_fetch_array($res))
{
$category .= '<option value="' . $row['id_cat'] . $row['destination']. '">' . $row['name'] . '</option>';
}
return $category;
}
So now it redirects each time to a different page depending of the option choose from the menu, like http://mydomain.com//3 then 4, 5, 6, etc.
But as the page doesn't exist, it redirects to a dead link.
Can someone give me help to create these pages from the chained menu (or have some highlight)? and if possible, some pointer to create the admin interface to allow an admin to add the pages and categories to the chained menu?
I've been trying to start with something which look like:
PHP Code:
<?php require('db_config.php');
$stmt = $db->prepare('SELECT id_type, name FROM type WHERE id_cat=$_POST[id]');
$stmt->execute(array(':id_cat' => $_GET['name']));
$row = $stmt->fetch();
However, I don't know if this is good at all.
if(file_exists($filename.'.php'))
echo "file : " . $filename.'.php' . " is exist";
else
{
$file = fopen($filename.'.php',"w");
$code="here what U want to write inside the new page.php";
fwrite($file,$code);
fclose($file);
}

add multiple times from a mysql time field in php

I have a table with the following structure and i want to get the sum of all the times for a certain album_id & disc. I found this http://board.phpbuilder.com/showthread.php?10326769-RESOLVED-time-help and it looked somewhat good (the first snippet of code in the first answer), but I cant figure out how to work it ith mysql...
Table Structure:
CREATE TABLE IF NOT EXISTS `tracks` (
`id` int(255) NOT NULL AUTO_INCREMENT,
`artist_id` int(255) NOT NULL,
`album_id` int(255) NOT NULL,
`disc` int(3) NOT NULL,
`track_no` int(3) NOT NULL,
`title` varchar(255) NOT NULL,
`length` time NOT NULL,
`size` decimal(20,1) NOT NULL,
`plays` int(255) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `artist_id` (`artist_id`,`album_id`,`disc`,`track_no`,`title`)
) ;
Any help is greatly appreciated. I'm a noob!!!
Maybe this will do.
SELECT album_id, disc, SEC_TO_TIME(SUM(TIME_TO_SEC(length))) AS formatTime
FROM tracks
GROUP BY album_id, disc
HAVING album_id=id AND disc=disc
Alternative for only a certain album and disc:
SELECT album_id, disc, SEC_TO_TIME(SUM(TIME_TO_SEC(length))) AS formatTime
FROM tracks
WHERE album_id=id AND disc=disc
//this is the album we want
$album = 24;
//grab all the track lengths and plays from our album
$query = '
SELECT length, plays
FROM tracks
WHERE album_id = "'.$album.'";
//do our mysql query
$result = mysql_query($query) or die(mysql_error());
//now for every result do somthing like add the length of the songs or play count
$length = null;
$plays = null;
while ($row = mysql_fetch_assoc($result)) {
$length = $length + $row["length"];
$pays = $plays + $row["plays"];
}
//echo data to user
echo 'The total lenth of this albums is:'.$length.'mins';
echo 'this ablum as been played:'.$plays.'times';

Function to check to see if a field in a MySQL table equals 1

For the MySQL table below, what PHP function would simply test to see if 'subcheck' equals 1?
Thanks in advance,
John
`submission` (
`submissionid` int(11) unsigned NOT NULL auto_increment,
`loginid` int(11) NOT NULL,
`title` varchar(1000) NOT NULL,
`slug` varchar(1000) NOT NULL,
`url` varchar(1000) NOT NULL,
`displayurl` varchar(1000) NOT NULL,
`datesubmitted` timestamp NOT NULL default CURRENT_TIMESTAMP,
`subcheck` tinyint(1) NOT NULL,
PRIMARY KEY (`submissionid`)
)
You haven't provided much needed information such as the table name, your conditions for checking, so I'm just going to give you a simple query for you to work with...
$query = mysql_query('SELECT subcheck FROM your_table WHERE subcheck = "1"');
if ($query)
{
//your subcheck is 1
}
else
{
//your subcheck is not 1 / nothing was found
}
If you need to select only ones with a certain submissionid it would be best to change it to the following:
$submissionid = 809;
$query = mysql_query('SELECT subcheck
FROM your_table
WHERE submissionid = "' . $submissionid . '"');
if ($row = mysql_fetch_row($query))
{
if ($row[0] == 1) { } //your subcheck is one
else { } //your subcheck is not one
}
else { } //no matching records found
Remember to escape $submissionid if it's going to be based from an unsafe source such as user input!

Get number of posts in a topic PHP

How do I get to display the number of posts on a topic like a forum. I used this... (how very noobish):
function numberofposts($n)
{
$sql = "SELECT * FROM posts
WHERE topic_id = '" . $n . "'";
$result = mysql_query($sql) or die(mysql_error());
$count = mysql_num_rows($result);
echo number_format($count);
}
The while loop of listing topics:
<?php
$sql = "SELECT * FROM topics ORDER BY topic_id ASC LIMIT $start, $limit";
$result = mysql_query($sql) or die(mysql_error());
while($row = mysql_fetch_array($result))
{
?>
<div class="topics">
<div class="topic-name">
<p><?php echo $row['topic_title']; ?></p>
</div>
<div class="topic-posts">
<p><?php echo numberofposts($row['topic_id']); ?></p>
</div>
</div>
<?php
}
?>
Although it is a bad method of doing this... All I need is to know what would be the best method, don't just point me out to a website, do it here, because I'm trying to learn much. Okay? :D
Thanks.
EDIT:
SQL:
Posts table:
CREATE TABLE `posts` (
`post_id` mediumint(8) NOT NULL AUTO_INCREMENT,
`topic_id` mediumint(8) NOT NULL,
`forum_id` mediumint(8) NOT NULL,
`user_id` mediumint(8) NOT NULL,
`post_time` varchar(100) NOT NULL,
`post_timestamp` mediumint(20) NOT NULL,
`post_ip` varchar(20) NOT NULL,
`post_reported` tinyint(1) NOT NULL,
`post_reportdesc` text NOT NULL,
PRIMARY KEY (`post_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
--
-- Dumping data for table `posts`
--
INSERT INTO `posts` VALUES(1, 1, 0, 1, '15th Junenee', 0, '', 0, '');
Topics table:
CREATE TABLE `topics` (
`topic_id` mediumint(8) NOT NULL AUTO_INCREMENT,
`section_name` varchar(25) NOT NULL,
`topic_title` varchar(120) NOT NULL,
`topic_description` char(120) NOT NULL,
`user_id` mediumint(8) NOT NULL,
`topic_time` varchar(100) NOT NULL,
`topic_views` varchar(1000) NOT NULL,
`topic_up` mediumint(11) NOT NULL,
`topic_down` mediumint(11) NOT NULL,
`topic_status` tinyint(1) NOT NULL,
PRIMARY KEY (`topic_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
This should help you understand a bit more.
You can use:
"SELECT COUNT(topic_id) FROM posts WHERE topic_id = '?'"
The ? is a place-holder. If you use mysql, you should use mysql_real_escape_string:
$sql = "SELECT COUNT(topic_id)
WHERE topic_id = '" . mysql_real_escape_string($n) . "'";
If you use mysql_fetch_array, $row[0] will be the count. You can name it but it's not necessary.
A better option is some kind of prepared statements, such as PDOStatement or mysqli_stmt. This helps prevent SQL injection.
When you're listing topics, you should include the post count in a join:
SELECT t.*, COUNT(p.post_id) AS post_count
FROM topic t LEFT JOIN posts p ON p.topic = t.topic_id
GROUP BY t.topic_id
Didn't study your schema too much, but you get the point.
You could use this SQL query instead if you only want the number of records:
SELECT COUNT(topic_id) AS 'count' WHERE topic_id = '123'
Then after you do:
$result = mysql_query($sql);
if ($result !== false)
{
$row = mysql_fetch_assoc($result);
if ($row !== false)
echo('Number of rows = ' . $row['count']);
}
SELECT topic_title, COUNT(*) AS toipic_count
FROM topics
GROUP BY topic_id
ORDER BY topic_id ASC
Then you will not need any more mysql-querys, just use:
$row['topic_count']

Categories