Let's first get to an important note about my situation:
I have 1 table in my MySQL database with approx 10 thousand entries
Currently, when collecting information from table #1. I collect a total of 20 - 24 rows per page.
Example being:
Q1 : SELECT * FROM table WHERE cat = 1 LIMIT 0,25
R1: id: 1, name: something, info: 12
The PHP file that does these queries, is called by the jquery ajax function, and creates an XML file that that jquery function reads and shows to the user.
My question here is. How do i improve the speed & stability of this process. I can have up to 10 thousand visitors picking up information at the same time, which makes my server go extremely sluggish and in some cases even crash.
I'm pretty much out of idea's, so i'm asking for help here. Here's an actual presentation of my current data collection (:
public function collectItems($type, $genre, $page = 0, $search = 0)
{
// Call Core (Necessary for Database Interaction
global $plusTG;
// If Search
if($search)
{
$searchString = ' AND (name LIKE "%'.$search.'%")';
}
else
{
$searchString = '';
}
// Validate Query
$search = $plusTG->validateQuery($search);
$type = $plusTG->validateQuery($type);
$genre = $plusTG->validateQuery($genre);
// Check Numeric
if((!is_numeric($genre)))
{
return false;
}
else
{
if(!is_numeric($type))
{
if($type != 0)
{
$typeSelect = '';
$split = explode(',',$type);
foreach($split as $oneType)
{
if($typeSelect == '')
{
$typeSelect .= 'type = '.$oneType.' ';
}
else
{
$typeSelect .= 'OR type = '.$oneType.' ';
}
}
}
}
else
{
$typeSelect = 'type = ' . $type . ' ';
}
//echo $typeSelect;
$limit = ($page - 1) * 20;
if(($type != 0) && ($genre != 0))
{
$items = $plusTG->db->query('SELECT * FROM dream_items WHERE active = 1 AND genre = '.$genre.' AND ('.$typeSelect.')'.$searchString.' ORDER BY name LIMIT '.$limit.',20');
$total = $plusTG->db->query('SELECT COUNT(*) as items FROM dream_items WHERE active = 1 AND genre = '.$genre.' AND ('.$typeSelect.')'.$searchString);
}
elseif(($type == 0) && ($genre != 0))
{
$items = $plusTG->db->query('SELECT * FROM dream_items WHERE active = 1 AND genre = '.$genre.$searchString.' ORDER BY name LIMIT '.$limit.',20');
$total = $plusTG->db->query('SELECT COUNT(*) as items FROM dream_items WHERE active = 1 AND genre = '.$genre.$searchString);
}
elseif(($type != 0) && ($genre == 0))
{
$items = $plusTG->db->query('SELECT * FROM dream_items WHERE active = 1 AND ('.$typeSelect.')'.$searchString.'ORDER BY name LIMIT '.$limit.',20');
$total = $plusTG->db->query('SELECT COUNT(*) as items FROM dream_items WHERE active = 1 AND ('.$typeSelect.')'.$searchString);
}
elseif(($type == 0) && ($genre == 0))
{
$items = $plusTG->db->query('SELECT * FROM dream_items WHERE active = 1'.$searchString.' ORDER BY name LIMIT '.$limit.',20');
$total = $plusTG->db->query('SELECT COUNT(*) as items FROM dream_items WHERE active = 1'.$searchString);
}
$this->buildInfo($items->num_rows, $total->fetch_assoc());
while($singleItem = $items->fetch_assoc())
{
$this->addItem($singleItem);
}
}
return true;
}
The build info call & add item call are adding the items to the DOMXML.
This is my javascript (domain and filename filtered):
function itemRequest(type,genre,page, search)
{
if(ajaxReady != 0)
{
ajaxReady = 0;
$('#item_container').text('');
var searchUrl = '';
var searchLink;
var ajaxURL;
if(search != 0)
{
searchUrl = '&search=' + search;
searchLink = search;
ajaxURL = "/////file.php";
}
else
{
searchLink = 0;
ajaxURL = "////file.php";
}
$.ajax({
type: "GET",
url: ajaxURL,
data: "spec=1&type="+type+"&genre="+genre+"&page="+page+searchUrl,
success: function(itemListing){
$(itemListing).find('info').each(function()
{
var total = $(this).find('total').text();
updatePaging(total, page, type, genre, searchLink);
});
var items = $(itemListing).find('items');
$(items).find('item').each(function()
{
var itemId = $(this).find('id').text();
var itemType = $(this).find('type').text();
var itemGenre = $(this).find('genre').text();
var itemTmId = $(this).find('tm').text();
var itemName = $(this).find('name').text();
buildItem(itemId, itemType, itemGenre, itemTmId, itemName);
});
$('.item_one img[title]').tooltip();
},
complete: function(){
ajaxReady = 1;
}
});
}
Build item calls this:
function buildItem(itemId, itemType, itemGenre, itemTmId, itemName)
{
// Pick up Misc. Data
var typeName = nameOfType(itemType);
// Create Core Object
var anItem = $('<div/>', {
'class':'item_one'
});
// Create Item Image
$('<img/>', {
'src':'///'+typeName+'_'+itemTmId+'_abc.png',
'alt':itemName,
'title':itemName,
click:function(){
eval(typeName + 'Type = ' + itemTmId);
$('.equipped_item[name='+typeName+']').attr('src','//'+typeName+'_'+itemTmId+'_abc.png');
$('.equipped_item[name='+typeName+']').attr('alt',itemName);
$('.equipped_item[name='+typeName+']').attr('title',itemName);
$('.equipped_item[title]').tooltip();
recentEquipped(typeName, itemTmId, itemName);
updateSelfy();
}
}).appendTo(anItem);
// Favs
var arrayHack = false;
$(favEquips).each(function(){
if(arrayHack == false)
{
if(in_array(itemTmId, this))
{
arrayHack = true;
}
}
});
var itemFaved = '';
if(arrayHack == true)
{
itemFaved = 'activated';
}
$('<div/>',{
'class':'fav',
'id':itemFaved,
click:function(){
if($(this).attr('id') != 'activated')
{
$(this).attr('id','activated');
}
else
{
$(this).removeAttr('id');
}
itemFav(itemTmId, typeName, itemName);
}
}).appendTo(anItem);
$(anItem).appendTo('#item_container');
}
If anyone could help me improve this code, it'd be very much appreciated.
add an index to your table for cat column
figure out what the bottleneck is, if it is your XML then try json,
if it is your network, try enabling gzip compression
I agree with Zepplock, it is important to find out where the bottleneck is - if not, you're only guessing. Zepplock's list is good but I would also add caching:
Find out where the bottleneck is.
Use indexes in your db table.
Cache your query results
Find the Bottleneck.
There are number opinions and ways to do this... Basically when your site is under load, get the time it takes to complete each step in the process: The DB queries, the server-side processes, the client side processes.
Use Indexes.
If your DB is slow chances are you can get a lot of improvement by optimizing your queries. A table index may be in order... Use 'EXPLAIN' to help identify where indexes should be placed to optimize your queries:
EXPLAIN SELECT * FROM dream_items WHERE active = 1 AND (name LIKE "%foo%") ORDER BY name LIMIT 0,20;
(I bet an index on active and name would do the trick)
ALTER TABLE `dream_items` ADD INDEX `active_name` (`active` , `name`);
Also try to avoid using the wildcard '*'. Instead only ask for the columns you need. Something like:
SELECT `id`, `type`, `genre`, `tm`, `name` FROM `dream_items` WHERE...
Cache Your Results.
If the records in the DB have not changed then there is no reason to try an re-query the results. Use some sort of caching to reduce the load on your DB (memcached, flat file, etc..). Depending on the database class / utilities you're using it may already be capable of caching results.
Related
I have an express server running using nodejs, and I'm using SQL syntax to query data from my MYSQL database.
The query is to get all members under the current user ID and also get members under it's children and so on, to get a genealogy tree. I'm trying to query a genealogy tree for a user.
I have a PHP script for the query, which worked fine
This is the PHP script:
$memory = $_GET['memory'];
echo '<div style="background:#ccc;display:flex;width:50px;height:50px;justify-
content:center;align-items:center;border-radius:50%;">'.$memory.'</div>';
$transend = array($memory);
$step = 1;
for ($i=0; $i < $step; $i++) {
$under = $transend[$i];
$get = $con->query("SELECT * FROM multilevel WHERE `under`='$under'");
$cnt = $get->num_rows;
if ($cnt>0) {
for ($g=0; $g < $cnt; $g++) {
$fet = $get->fetch_object();
$id = $fet->id;
$position = $fet->position;
array_push($transend, $id);
$step = $step*2;
echo '<div style="background:#ccc;display:flex;width:50px;height:50px;justify-content:center;align-items:center;border-radius:50%;">'.$id.'-'.$position.'</div>';
}
} else {
break;
}
}
I am trying to rewrite it using SQL syntax in node. This is my nodejs code:
A Tree Constructor
const Tree = function (binary) {
this.position = binary.position;
this.level = binary.level;
this.user_id = binary.user_id;
this.under_user_id = binary.under_user_id;
this.brought_by = binary.brought_by;
this.username = binary.username;
};
A method to get all binary for a user
Tree.findBinaries = async (id, result) => {
const theId = parseInt(id);
let transend = [theId];
let step = 1;
let data = [];
for (let i = 0; i < step; i++) {
const under = transend[i];
connection.query(
`SELECT * FROM multilevel WHERE under = ?`,
under,
(err, res) => {
if (err) {
result(null, err);
return;
}
if (res.length) {
for (let index = 0; index < res.length; index++) {
const { id } = res[index];
// push id
transend.push(id);
data.push(res[index]);
step = step * 2;
}
result(null, data);
} else {
result(null, "no data found");
}
}
);
}
};
The transend.push(id) and data.push(res[index]), are not been pushed to the top level, also the step is not been updated. So the loop is running just once.
The expected Result is supposed to be 16 items of children and children of children, But it is currently returning to just the first level. I don't know what I'm currently doing wrong.
I need to update a table with more then 12000 row using php Codeigniter and a txt file.. reading the file and the foreach loop are fine but when updating line by line it takes like 30 mins, I guess the problem is I'm searching by name because I have no id in the txt file...
Here is my code:
controller:
$fn = fopen($this->upload->data('full_path'),"r");
$update = true;
while(! feof($fn) && $update) {
$pieces = explode("|", fgets($fn));
if(sizeof($pieces) == 9 && is_numeric(trim($pieces[1]))) {
$update = $this->model_products->update3s($pieces);
}
}
fclose($fn);
Model:
public function update3s($product) {
if ($product) {
$product[2] = trim(str_replace("'","''",$product[2]));
$product[1] = trim($product[1]);
$product[6] = trim($product[6]);
$product[3] = trim($product[3]);
$sql = "UPDATE products set qty = $product[3], price_vente = $product[6] where (name = '$product[2]')";
echo $sql.'<br>';
$update = $query = $this->db->query($sql);
return $update;
}
return false;
}
You can use transaction and add index for column name in database table.
$fn = fopen($this->upload->data('full_path'),"r");
$update = true;
$updatedCount = 0;
while(! feof($fn) && $update) {
$pieces = explode("|", fgets($fn));
if(sizeof($pieces) == 9 && is_numeric(trim($pieces[1]))) {
if ($updatedCount == 0) {
$databaseInstance->beginTransaction();
}
$update = $this->model_products->update3s($pieces);
++$updatedCount;
if ($updatedCount > 500) { //in one transaction update 500 rows
$databaseInstance->commit();
$updatedCount = 0;
}
}
}
if ($updatedCount > 0) { // if we have not commited transaction
$databaseInstance->commit();
}
fclose($fn);
Some tips
Add index to field name
Use prepared statements
Disable the MySQL forgeign key check Read more
writing sql function can do that even in much lesser time .
using feature like :
REPLACE()
cursors
SPLIT_STRING(custom)
in a mysql user defined function
CREATE FUNCTION update3s(hole_file_content LONGTEXT) RETURNS Boolean
BEGIN
-----Your implementation(same logic in sql ) ------
END
then coll it just by if it is CI 3
$this->db->call_function('update3s', file_get_contents($this->upload->data('full_path')));
else
$this->db->query("select update3s(".file_get_contents($this->upload->data('full_path')).")");
I am inserting a serial number in a table that is increment by one always but when multiple request is coming in same time it is inserting same serial number for different requests.I am using mysql database.
I know i am fetching the max serial number too early in the code and if request is come in same time so it will fetching same serial number for both. is it good idea to update serial number after all work done. what if inserting a record for new request and updating the serial number for previous one is in same time.
public function add(){
$session = $this->request->session();
$company_id = $session->read('Admin.company_id');
$emp_id = $session->read('Admin.emp_id');
$user_email_id = $session->read('Admin.email_id');
$employee_name = $session->read('Admin.employee_name');
$conn = ConnectionManager::get('default');
if ($this->request->is('post')) {
try{
$conn->begin();
$department = $this->request->data['department'];
$data = $this->request->data;
if(!array_key_exists('is_requisition_for_contractor', $data)){
$is_requisition_for_contractor = 0;
} else {
$is_requisition_for_contractor = $data['is_requisition_for_contractor'];
}
if(!array_key_exists('is_requisition_for_employee', $data)){
$is_requisition_for_employee = 0;
} else {
$is_requisition_for_employee = $data['is_requisition_for_employee'];
}
if(!array_key_exists('is_boulder_requisition', $data)){
$is_requisition_for_boulder = 0;
} else {
if($data['is_boulder_requisition'] == ''){
$is_requisition_for_boulder = 0;
} else {
$is_requisition_for_boulder = $data['is_boulder_requisition'];
}
}
$is_requisition_for_plant = 0;
if(!array_key_exists('is_plant_requisition', $data)){
$is_requisition_for_plant = 0;
} else {
if($data['is_plant_requisition'] == ''){
$is_requisition_for_plant = 0;
} else {
$is_requisition_for_plant = $data['is_plant_requisition'];
}
}
if(array_key_exists("files",$this->request->data)) {
$files = $this->request->data['files'];
if (count($files)) {
$files_uploading_response = $this->uploadMultipleFiles($files, 'files/requisitions/');
}
}
$last_material_insert_id = '';
if($this->request->data('material_id')[0] == ''){
if($this->request->data('department') == 1){
$type = 1;
} elseif($this->request->data('department') == 3){
$type = 3;
} elseif($this->request->data('department') == 2){
$type = 2;
}
if($this->request->data('department') == 1 || $this->request->data('department') == 3){
$conn->execute("INSERT INTO material (material_name, material_type_id, company_id, status, is_approved_by_admin) VALUES (?,?,?,?,?)",[$this->request->data('material_name'), $type, $company_id, 1,0]);
$last_material_insert_id = $conn->execute("SELECT LAST_INSERT_ID() AS last_id")->fetchAll('assoc');
} elseif($this->request->data('department') == 2) {
//todo for unapproved material
$conn->execute("INSERT INTO material (part_no, material_type_id, company_id, status, is_approved_by_admin,unique_category_id) VALUES (?,?,?,?,?,?)",[$this->request->data('part_no')[0], $type, $company_id, 1,0,$this->request->data('unique_category_id')[0]]);
$last_material_insert_id = $conn->execute("SELECT LAST_INSERT_ID() AS last_id")->fetchAll('assoc');
}
}
// here i am fatching max serial number from table
$requistion_number = $conn->execute("SELECT IF(MAX(requisition_no) IS NULL, 0,MAX(requisition_no)) AS requisition_no FROM requisition WHERE site_id = ?",[$this->request->data('site_id')])->fetchAll('assoc');
$Requisition = TableRegistry::get('requisition');
$requisition = $Requisition->newEntity();
$requisition->registered_on = $this->request->data['date'];
$requisition->department_id = $this->request->data('department');
$requisition->site_id = $this->request->data('site_id');
$requisition->issues_to_id = $this->request->data['prepared_by_id'];
$requisition->prepared_by_id = $this->request->data['prepared_by_id'];
$requisition->approved_by_id = $this->request->data['hod_id'];
$requisition->hod_id = $this->request->data['hod_id'];
$requisition->is_diesel_requisition_for_employee = $is_requisition_for_employee;
$requisition->is_diesel_requisition_for_contractor = $is_requisition_for_contractor;
$requisition->is_requisition_for_boulder = $is_requisition_for_boulder;
$requisition->is_requisition_for_plant = $is_requisition_for_plant;
if(array_key_exists('for_tanker_stock', $this->request->data)) {
$requisition->for_tanker_stock = 1;
}
if($last_material_insert_id != ''){
$requisition->is_material_approved_by_admin = 0;
}
$requisition->status = 1;
$site_id = $this->request->data['site_id'];
$requisition->requisition_no = $requistion_number[0]['requisition_no'] + 1;
$requistionnumber = $requistion_number[0]['requisition_no'] + 1;
$saveRequsition = $Requisition->save($requisition);
$conn->commit();
}
I am expecting the output different serial number for each request.any optimise way to do this. thanks in advance.
Ok, how about the same strategy, setting the $requisition_number after the row has been inserted (see my other answer), but using a single query with the same method you use to determine the new requisition id:
$conn->execute("UPDATE requisition
SET requisition_no = (SELECT IF(MAX(requisition_no) IS NULL, 0,MAX(requisition_no)) AS requisition_no FROM requisition WHERE site_id = ?) + 1",
[$this->request->data('site_id')]);
The idea here is that a single query will be executed in one step, without another, similar query, being able to interfere.
What you currently do is to first get the old requistion number like this:
$requistion_number = $conn->execute("SELECT IF(MAX(requisition_no) IS NULL, 0,MAX(requisition_no)) AS requisition_no
FROM requisition WHERE site_id = ?",[$this->request->data('site_id')])->fetchAll('assoc');
and then increase it before you save and commit.
My suggestion is to not set the $requistion_number at all before you save and commit the requisition row, but to determine the $requistion_number afterwards.
You now wonder how?
Well, you need to count the total number of requisition rows in the table for the site the requisition is for, and add one, like this:
$last_requisition_id = $conn->execute("SELECT LAST_INSERT_ID() AS last_id")->fetchAll('assoc');
$site_id = $this->request->data('site_id');
$requisition_number = $conn->execute("SELECT COUNT(*) AS requisitionsCount
FROM requisition
WHERE <primary_key> <= ? AND
site_id = ?",
[$last_requisition_id, $site_id]) + 1;
$conn->execute("UPDATE requisition
SET requisition_no = ?
WHERE <primary_key> <= ?",
[$requisition_number, $last_requisition_id]);
I know this code is not working. The $requisition_number will probably contain an array with the requisitionsCount as a value, but you can correct that.
Because you're using data that is already present in the database table you don't run the risk that two rows will get the same $requisition_number. The assumption here is that requisitions are never deleted.
i have a categories table
(id=1 , name=Hand made, parent=0)
(id=2 , name=Factory made, parent=0)
(id=3 , name=chairs, parent=1)
(id=4 , name=tabels, parent=1)
(id=5 , name=old chairs, parent=3)
at the menu if visitor clicked on category OLD CHAIRS , will go to page
products.php?category_id = 5
then at this page i need to know what is the main category_id , which should be HAND MADE with category_id=1
so at this page i want to say
if isset($_REQUEST['category_id']){
do the function till find the main parent,
$mainparentid = main parent category_id
}else { $mainparentid = '';
} echo $mainparentid;
here is my PHP Code
if (isset($_REQUEST['category_id'])) {
function getParent($id) {
global $connection;
$query_rsCategoryId = "SELECT * FROM categories
WHERE category_id = '".$_REQUEST['category_id']."'";
$rsCategoryId = mysql_query($query_rsCategoryId, $connection);
$row_rsCategoryId = mysql_fetch_assoc($rsCategoryId);
$parent = $row_rsCategoryId['category_parent'];
if (mysql_num_rows($rsCategoryId) < 1) {
// Error handling, entry with id $id not found
return null;
}
if ($parent == 0) {
return $id;
} else {
return getParent($parent);
}
}
$mainparentid = getParent($id);
}else {
$mainparentid ='none';
}
echo $mainparentid ;
You always input ID of the category from $_REQUEST. Change line:
WHERE category_id = '".$_REQUEST['category_id']."'";
to:
WHERE category_id = '".$id."'";
You are using parent id from request instead of given via function parameter
// notice $id instead of $_REQUEST['category_id']
$query_rsCategoryId = "SELECT * FROM categories WHERE category_id = '{$id}'";
I have two queries sent to a database bring back posts (op_ideas 16 cols) followed by another which holds the votes per post (op_idea_vote cols 4) with matching idea_id's
Example of Data:
Query: op_ideas:
[{"idea_id":"2211","author_id":"100000", "date":"2012-09-06
10:02:28","idea_title":"Another test","4" etc etc
Query: op_idea_votes:
idea_id = 2211, agree=3, disagree=1, abstain=0
The code below ought to look at op_ideas, and then cycle over op_ideas_vote until it finds a match under 'idea_id'. Then it goes to the next record under op_ideas, and again using that idea_id search for it within the op_idea_vote list, find a match, and add it to the array.
This works for only the first record, not for the other three. I am testing, so I have 3 rows in each that match idea_id with different results in the op_idea_vote.
$votes = mysql_query($commentVotes);
$result = mysql_query($gl_query);
while ($gce_result = mysql_fetch_array($result)) {
$voteid = $gce_result['idea_id'];
while($allvotes= mysql_fetch_array($votes)) {
if($voteid = $allvotes['idea_id'])
{
//echo $voteid . " main idea and the votes: " . $allvotes;
$gce_result["agree"] = $allvotes['agree'];
$gce_result["disagree"] = $allvotes['disagree'];
$gce_result["abstain"] = $allvotes['obstain'];
}
else
{
$gce_result["agree"] = 0;
$gce_result["disagree"] = 0;
$gce_result["abstain"] = 0;
}
//print_r($gce_result);
}
$data_result[] = $gce_result;
}
echo json_encode($data_result);
If I use print_f(&gce_result) it works fine in phpfiddle. But when i use the code above, it works for the first record, but it's complete missing the second two. It seems to be missing the second while, as it does not even give me the 0 0 0 results.
Query for op_ideas:
$gl_query = "SELECT DISTINCT * FROM heroku_056eb661631f253.op_ideas INNER JOIN op_organs ORDER BY date ASC;";
if (!mysql_query($gl_query)) {
die('Error: ' . $gl_query . " " . mysql_error());
}
$result = mysql_query($gl_query);
Query For op_idea_vote :
$commentVotes = "SELECT v.idea_id, COUNT(v.agree = 1 or null) as agree, COUNT(v.disagree = 1 or null) as disagree, COUNT(v.obstain = 1 or null) as obstain FROM op_idea_vote v GROUP BY v.idea_id";
if (!mysql_query($commentVotes)) {
die('Error: ' . $commentVotes . " " . mysql_error());
}
$votes = mysql_query($commentVotes);
You can scan a resource only once.
So the inner while will be run only one time.
use == instead of = for checking condition of if & while
in the while loop ,you have to assign the value of $allvotes ,but you never assigned,
while ($gce_result == mysql_fetch_array($result)) {
$voteid = $gce_result['idea_id'];
while($allvotes== mysql_fetch_array($votes)) {
if($voteid == $allvotes['idea_id'])
{
//echo $voteid . " main idea and the votes: " . $allvotes;
$gce_result["agree"] = $allvotes['agree'];
$gce_result["disagree"] = $allvotes['disagree'];
$gce_result["abstain"] = $allvotes['obstain'];
}
else
{
$gce_result["agree"] = 0;
$gce_result["disagree"] = 0;
$gce_result["abstain"] = 0;
}
$data_result[] = $gce_result;
}
}
Your problem is trying to scan over the $votes result more than once.
You should store the result of that query first.
Eg.
while ($vote = mysql_fetch_array($votes)) {
$allvotes['idea_id'] = $vote;
}
while ($gce_result = mysql_fetch_array($result)) {
$voteid = $gce_result['idea_id'];
if (array_key_exists[$voteid, $allvotes]) {
//assign results
} else {
//default
}
}
Another option would be to do the query with a join, so you can do everything in one query. Then just loop over that result.