I have a question regarding to the performance between a lookup table stored in MySQL (standalone table) or PHP (array), so here is my data (in array form)
$users = array(
array(name => 'a', address => 'abc', age => '14'),
array(name => 'b', address => 'def', age => '12'),
array(name => 'c', address => 'ghi', age => '13'),
array(name => 'd', address => 'jkl', age => '14'),
array(name => 'd', address => 'mno', age => '11'),
);
It is a game on the facebook platform, may have a chance with a lot people access in same time.
Actually, the table should have ~100 rows, but all data is static, if all data store in MySQL, I can do any "select" easily, consider with too much query to MySQL, therefore I consider store in php array, however, I don't know how to select rows in a specific condition (I know it should have other other method rather than for loop) just like select all age = 14 in to another array.
So, which one have the better performance? (MySQL or PHP lookup table?)
If you know:
the data will always be static
that you'll only have 100 rows
that you'll only ever be using simple single-field matches in your queries
that you'll never need advanced features like joins
that you're going to get high traffic
... then I'd definitely put the logic in pure PHP. "Remove unnecessary database queries" is always going to be your first step in improving performance, and dropping these dead-simple rows into MySQL for no other reason than you don't want to write a simple foreach loop is a bad idea, I think. It's overkill. If you're using a opcode cache like APC (which you are, right?) then I don't think the performance comparison will even be close. (Though I'll always recommend actually benchmarking them both yourself to be sure.)
class Users
{
protected $_users = array(
array('name' => 'a', 'address' => 'abc', 'age' => '14'),
array('name' => 'b', 'address' => 'def', 'age' => '12'),
array('name' => 'c', 'address' => 'ghi', 'age' => '13'),
array('name' => 'd', 'address' => 'jkl', 'age' => '14'),
array('name' => 'e', 'address' => 'mno', 'age' => '11')
);
public function select($field, $value)
{
$list = array();
foreach ($this->_users as $user) {
if ($user[$field] == $value) {
$list[] = $user;
}
}
return $list;
}
}
$users = new Users();
$list = $users->select('age', 14);
PHP will be definitely faster in terms of performance. But querying will be difficult to maintain code. Keeping data in mysql will be a overhead because of network. But you can optimize that by using MyIASM tables and using query cached on server side.
My vote is for MyIASM table on MySql with query cache enabled.
Related
I am trying to create a select input field. However I want to set the values of each individual option manually.
in an attempt I tried the following:
echo $this->Form->input('field', array(
'options' => array('Active', 'Blocked', 'Pending', 'Unknown'),
'values' => array(1,2,0,99),
'empty' => '(choose one)'
));
However this did not help (i.e 'Active' was 0, 'Blocked' was 1 etc...)
Does anyone know if it is possible to manually set the values?
values is not the right key, you need to leverage the options array for it, as well:
'options' => array(1 => 'Active', 2 => 'Blocked', 0 => 'Pending', 99 => 'Unknown'),
but that is basic PHP (since non-defined keys are numerically indexed starting off at 0).
You’ll need to use an associative array to set the keys as well:
$options = array(
'1' => 'Active',
'2' => 'Blocked',
'0' => 'Pending',
'99' => 'Unknown'
);
echo $this->Form->input('field', array('options' => $options));
However, I’d advise storing options like this in a separate database table rather than hard-coding them, to keep your views DRY and allowing them to be easily modified in the future.
Here is the query string.
$query = "SELECT t.id, t.assignee, t.owner,
d.code, d.status, d.target_completion_date,
d.target_extension_date, d.submission_date, d.approval_date,
d.revision_start_date, d.revision_completion_date, d.message,
ty.name, f.orig_name, f.new_name,
b.payment_date, b.discount, b.total_cost, b.amount_payed, b.edit_level,
b.billing_type, b.pages, b.words
FROM tasks t
INNER JOIN details d ON t.detail_id = d.id
INNER JOIN billing b ON t.billing_id = b.id
INNER JOIN TYPE ty ON d.document_type_id = ty.id
INNER JOIN files f ON t.file_id = f.id
WHERE t.assignee = 'argie1234'";
And this is the array i would like the query result to turn into.
$user = array('allTask'=>array(array('taskid' => 1,
'assignee'=>'argie1234',
'owner'=>'austral1000',
'details' => array( 'code' => 'E',
'status'=>'TC',
'targetCompletionDateUTC'=>'1379401200',
'targetExtentionDateUTC'=>'1379401200',
'submissionDateUTC'=>'1379401200',
'approvalDateUTC'=>'1379401200',
'revisionStartDateUTC'=>'1379401200',
'revisionCompletionDateUTC'=>'1379401200',
'messageToEditor'=>'Please work on it asap.',
'documentType' => 'Thesis'),
'file' => array('orig_name' =>'originalname.docx',
'new_name' => 'newname.docx'),
'billing'=>array('paymentDate'=>'July 26,2013 12:40',
'discount' => '0',
'totalRevisionCharge' => '$20.00',
'totalAmountPayed' => '$20.00',
'revisionLevel' => '1',
'chargeType'=> '1',
'numPages' => '60',
'numWords' => '120,000' ) ),
array('taskid' => 12,
'assignee'=>'argie1234',
'owner'=>'usaroberto',
'details' => array( 'code' => 'E',
'status'=>'TC',
'targetCompletionDateUTC'=>'1379401200',
'targetExtentionDateUTC'=>'1379401200',
'submissionDateUTC'=>'1379401200',
'approvalDateUTC'=>'1379401200',
'revisionStartDateUTC'=>'1379401200',
'revisionCompletionDateUTC'=>'1379401200',
'messageToEditor'=>'Please work on it asap.',
'documentType' => 'Thesis'),
'file' => array('orig_name' => 'originalname.docx',
'new_name' => 'newname.docx'),
'billing'=>array('paymentDate'=>'July 26,2013 12:40',
'discount' => '0',
'totalRevisionCharge' => '$20.00',
'totalAmountPayed' => '$20.00',
'revisionLevel' => '1',
'chargeType'=> '1',
'numPages' => '60',
'numWords' => '120,000' ) ),
'account' => array( 'username' => 'marooon55',
'emailadd' => 'marooon#yahoo.com',
'firstname' => 'Maroon',
'initial' => 'E',
'lastname' => 'Young',
'country' => 'Australia',
'gender' => 'M',
'password' =>'360e2801190744a2af74ef6cbfdb963078b59709',
'activationDate' => '2013-09-13 14:30:34') );
How can i create the above array? I sure know how to define multi dimensional array, regretfully though i am having difficulty creating this complex array dynamically. As a beginner i don't even know where to begin.
Here is an example that might help you out. Try starting with simple multi dimensional arrays, once you get a hold of it, you can move onto building complex ones. You will then find that the array you want to build is not really difficult than you initially thought it to be.
$mycomplexarray = array('key1' => array('val1', 'val2'),
'key2' => array('val3', 'val4' => array('val5', 'val6')
)
);
You could create the array just as you have here. I'm not gonna write the whole thing out, but something like this...
$result = $mysqli->query($query); // however you query the db is up to you.
$row = $result->fetch_assoc(); //same as query use your prefered method to fetch
$user = array('allTask'=>array(array('taskid' => $row['id'],
'assignee'=>$row['assignee'],
'owner'=>$row['owner'],
'details' => array( 'code' => $row['code'],
'status'=>$row['status'],
...etc, Hope this makes sense for you.
Set up a structure array first that defines which columns will be stored in a sub array like
$struc=array('Id'->0, 'assignee'->0, 'owner'->0,
'code'->'detail', 'status'->'detail', 'target_completion_date'->'detail',
'target_extension_date'->'detail', 'submission_date'->'detail', 'approval_date'->'detail',
'revision_start_date'->'detail', 'revision_completion_date'->'detail', 'message'->'detail',
'name'->'file', 'orig_name'->'file', 'new_name'->'file',
'payment_date'->'billing', 'discount'->'billing', 'total_cost'->'billing', 'amount_payed'->'billing', 'edit_level'->'billing', 'billing_type'->'billing', 'words');
In your while ($a=mysqli_fetch_assoc($res)) loop you can now use this structure to decide whether you want to store an element directly in your target array or whether you want to place it in the subarray named in this structure array. Like
$res=mysqli_query($con,$sql);
$arr=array();
while($a=mysqli_fetch_assoc($res)) {
// within result loop: $a is result from mysqli_fetch_assoc()
$ta=array(); // temp array ...
foreach ($a as $k => $v){
if ($struc[$k]) $ta[struc[$k]][$k]=$v;
else $ta[$k]=$v;
}
$arr[]=$ta; // add to target array
}
This is the complete code, no more is needed. It was typed up on my iPod, so it is NOT tested yet.
The generated array should be equivalent to your $user['allTask'] array.
example
public $inputs=array(
array( 'sysname'=>'pt_name','dbname' => 'users.name','label' => 'user (name/ID)','value' => '',
'type' => 'text','rules' => 'required','attr'=>'class="autocomplete"'),
array( 'sysname'=>'pt_dob','dbname' => 'users.dob','label' => 'Patient Dob','value' => '',
'type' => 'text','rules' => 'required','attr'=>'class="dob ac" Disabled'),
array( 'sysname'=>'pt_gender','dbname' => 'users.gender','label' => 'gender','value' => 'male,female',
'type' => 'dropdown','rules' => 'required','attr'=>'class="ac" Disabled'),
array( 'sysname'=>'visit_date','dbname' => 'visits.date','label' => 'Date','value' => '',
'type' => 'text','rules' => 'required','attr'=>'class="datepicker"'),
array( 'sysname'=>'visit_time','dbname' => 'visits.time_booked','label' => 'Time','value' => '',
'type' => 'text','rules' => 'required','attr'=>'class="timepicker"'),
array( 'sysname'=>'visit_type','dbname' => 'visits.type','label' => 'Visit type','value' => 'visit,schedule',
'type' => 'dropdown','rules' => 'required','attr'=>'')
);
how can i search this array for only arrays that have pt_ in its sysname for example ?
the idea is i have many types of rows all in same table, so instead of running a mysql query to fetch each type separatly example:
$pt=db->query("select * from table where sysname like 'pt_%'")->result();
$visit=db->query("select * from table where sysname like 'visit_%'")->result();
i want to fetch all at one and split them in php to decrease db load.
so how can i do this ? and is it worth it or better of keep my querys separate.
array_filter and a PHP-style closure* would be a pretty simple solution to this:
function buildFilter($key, $needle) {
return function($array) use($key, $needle) {
return (strpos($array[$key], $needle) !== FALSE);
};
}
$matches = array_filter($inputs, buildFilter('sysname', 'pt_'));
var_dump($matches);
NB: What PHP calls a "closure" is quite a bit different from what most other languages use for the same term, so please make sure to read the PHP documentation.
Doing a couple of queries is fine, your DB can handle that easily. If you're doing dozens of queries for dozens of types (each with only a few rows), it might be worth investigation moving that logic to PHP.
What I would recommend is to put the systype in a separate column with an index on it. That will speed of your query a lot and take load of your DB. Even better is you can make that column an ENUM.
public $inputs=array(
array( 'systype'=>'pt', 'sysname'=>'pt_name','dbname' => 'users.name','label' => 'user (name/ID)','value' => '',
'type' => 'text','rules' => 'required','attr'=>'class="autocomplete"'),
...
$pt=db->query("select * from table where systype = 'pt'")->result();
$visit=db->query("select * from table where systype = 'visit'")->result();
if I have a muli-dimensional array like that I take from a form submit:
$participants = array(
'participant1'=> array(
'name'=>'jim',
'age' => '15',
'grade' => '8th'),
'participant2'=> array(
'name'=>'tom',
'age' => '17',
'grade' => '9th'),
....
);
Is it better two store whole array into one db column named "Participants" or create a separate column in the row for each participant PERFORMANCE wise if i have a maximum number of participants?
using separate column would be better at the point of normalization also if you need only name or age than it would be better you dont need to fetch all
I'm trying to join two associative arrays together based on an entry_id key. Both arrays come from individual database resources, the first stores entry titles, the second stores entry authors, the key=>value pairs are as follows:
array (
'entry_id' => 1,
'title' => 'Test Entry'
)
array (
'entry_id' => 1,
'author_id' => 2
I'm trying to achieve an array structure like:
array (
'entry_id' => 1,
'author_id' => 2,
'title' => 'Test Entry'
)
Currently, I've solved the problem by looping through each array and formatting the array the way I want, but I think this is a bit of a memory hog.
$entriesArray = array();
foreach ($entryNames as $names) {
foreach ($entryAuthors as $authors) {
if ($names['entry_id'] === $authors['entry_id']) {
$entriesArray[] = array(
'id' => $names['entry_id'],
'title' => $names['title'],
'author_id' => $authors['author_id']
);
}
}
}
I'd like to know is there an easier, less memory intensive method of doing this?
Is it possible you can do a JOIN in the SQL used to retrieve the information from the database rather than fetching the data in multiple queries? It would be much faster and neater to do it at the database level.
Depending on your database structure you may want to use something similar to
SELECT entry_id, title, author_id
FROM exp_weblog_data
INNER JOIN exp_weblog_titles
ON exp_weblog_data.entry_id = exp_weblog_titles.entry_id
WHERE field_id_53 = "%s" AND WHERE entry_id IN ("%s")
Wikipedia has a bit on each type of join
Otherwise the best option may be to restructure the first array so that it is a map of the entry_id to the title
So:
array(
array(
'entry_id' => 1,
'title' => 'Test Entry 1',
),
array(
'entry_id' => 3,
'title' => 'Test Entry 2',
),
)
Would become:
array(
1 => 'Test Entry 1',
3 => 'Test Entry 2',
)
Which would mean the code required to merge the arrays is simplified to this:
$entriesArray = array();
foreach ($entryAuthors as $authors) {
$entriesArray[] = array(
'id' => $authors['entry_id'],
'title' => $entryNames[$authors['entry_id']],
'author_id' => $authors['author_id']
);
}
I've rearranged some of my code to allow for a single SQL query, which looks like:
$sql = sprintf('SELECT DISTINCT wd.field_id_5, wd.entry_id, mb.email, mb.screen_name
FROM `exp_weblog_data` wd
INNER JOIN `exp_weblog_titles` wt
ON wt.entry_id=wd.entry_id
INNER JOIN `exp_members` mb
ON mb.member_id=wt.author_id
WHERE mb.member_id IN ("%s")
AND wd.entry_id IN ("%s")',
join('","', array_unique($authors)),
join('","', array_unique($ids))
);
This solves my problem quite nicely, even though I'm making another SQL call. Thanks for trying.
In response to your comment on Yacoby's post, will this SQL not give the output you are after?
SELECT exp_weblog_data.entry_id, exp_weblog_data.field_id_5 AS title_ie, exp_weblog_titles.author_id
FROM exp_weblog_data LEFT JOIN exp_weblog_titles
ON exp_weblog_data.entry_id = exp_weblog_titles.entry_id
WHERE exp_weblog_data.field_id_53 = "%S"
Every entry in exp_weblog_data where field_id_53 = "%S" will be joined with any matching authors in exp_weblog_titles, if a an entry has more than one author, two or more rows will be returned.
see http://php.net/manual/en/function.array-merge.php