How to speed this query up? - performance

I'm using yii framework to create a website takes care of poems and words and stuff...
the problem is that the database has more than 250,000 record of messages and more than 500,000 records of keywords and relationships :S
what I'm trying to say that I want to make an optimal query to get all related messages of a specific message depending on key-tags..
what I did so far is caching the query, but it's still slow when opening it for the first time and that's a big problem!
here is my code:
public function getRelatedMessages()
{
$id = $this->id;
$dependency = "select `messages`.id,count(id) as tag_count from messages left join `messages_tags` on `messages`.`id` = `messages_tags`.mid
where `messages_tags`.`tagid` in (select `tags`.`id` from tags left join `messages_tags` on tags.id = `messages_tags`.tagid
where `messages_tags`.`mid` = {$id}) and id <> {$id} group by id order by tag_count desc";
$dependency = Messages::model()->cache(900)->findAllBySql($dependency);
foreach ($dependency as $dependency) {
$dependency1[] = $dependency['id'];
}
$dependency = implode(", ", $dependency1);
$sql = "select * from messages where id in ({$dependency}) limit 4";
$relateds = Messages::model()->findAllBySql($sql);
$db = array();
foreach($relateds as $related) {
$db[] = $related;
}
if(!$relateds || count($db)<4) {
$limit = 4-count($db);
$sql = "select `messages`.id, `messages`.url_key, `messages`.photo_url, `messages`.message from messages order by rand(), likes desc, comments desc, impressions desc, reported asc limit {$limit};";
$relateds = Messages::model()->cache(900)->findAllBySql($sql);
foreach($relateds as $related) {
$db[] = $related;
}
}
return $db;
}
the code above selects only 4 records from the related messages after filtering them and ordering them and stuff.. the problem is with "order by" but I need it :S
sorry if that was too long..
thank you :)

You could improve the first query by not using findAllBySql() and instantiating all the ActiveRecord classes. You don't need them, so use plain sql query like this (query stays the same but code around has changed):
// ...
$dependency = $this->dbConnection->createCommand("
select `messages`.id, count(id) as tag_count
from messages left join `messages_tags` on `messages`.`id` = `messages_tags`.mid
where
`messages_tags`.`tagid` in
(select `tags`.`id` from tags left join `messages_tags` on tags.id = `messages_tags`.tagid where `messages_tags`.`mid` = {$id})
and id <> {$id}
group by id order by tag_count desc")->queryColumn();
$dependency = implode(", ", $dependency);
$sql = "select * from messages where id in ({$dependency}) limit 4";
$relateds = Messages::model()->findAllBySql($sql);
// ...

Related

how to use order by random in codeigniter

While Searching I want to show the paid customers firstly, and then rest of customers list
but the problem is I want to show by random
for Example. paid customers should not mix with others.
Can anyone tell what will be query?
please help me!
I am using codeigniter
Example:
function randomval()
{
$this->db->order_by('id', 'RANDOM');
$this->db->limit(1);
$query = $this->db->get('tblname');
return $query->result_array();
}
Mysql query for your need if i understood well
SELECT `featured`,group_concat(`id` order by rand() ) as `id` FROM `dbc_posts` where `status` = 1 GROUP By `featured` ORDER BY `featured` DESC
now with php
$results = $this->db->query("SELECT `featured`,group_concat(`id` order by rand() ) as `id` FROM `dbc_posts` where `status` = 1 GROUP By `featured` ORDER BY `featured` DESC")->result_array();
$paid = $results[0];//featured = 1
// comma seprated ids of the paid people e.g :- 3,7,1,26,92 are available in
$paidusers = $results[0]["id"];
//seprate them by
$paidusers = explode(",",$paidusers);
foreach($paidusers as $paiduser)
{
$row = $this->db->get_where("dbc_posts", array("id"=> $paiduser))->row();
print_r($row );
echo "<br>";
}
// do same for unpaid
$unpaid = $results[1];//featured = 0
$unpaidusers = $results[1]["id"];
//seprate them by
$unpaidusers = explode(",",$unpaidusers);
foreach($unpaidusers as $unpaiduser)
{
$row = $this->db->get_where("dbc_posts", array("id"=> $unpaiduser))->row();
print_r($row );
echo "<br>";
}
Ask me if anything goes wrong
Set featured = 1 for paid and featured = 0 for unpaid customers in database. Then use the query
mysql_query("SELECT * FROM dbc_posts WHERE status = 1 ORDER BY featured DESC, RAND() LIMIT 1");

Doctrine create subquery with bound params

I am trying to construct a query that will basically pull all entries whose id's have 2 particular entries in another table so I am trying the below:
$query = $this->createQuery('e');
$subquery1 = $query->createSubquery('sea')
->select('sea.entry_id')
->from('Table sea')
->addWhere('sea.form_element_id = ?', $element)
->addWhere('sea.answer = ?', $answer)
->getDQL();
$subquery2 = $query->createSubquery('sea2')
->select('sea2.entry_id')
->from('Table sea2')
->addwhere('sea2.form_element_id = ?', $element2)
->addWhere('sea2.answer = ?', $answer2)
->getDQL();
$query->addWhere('e.id IN ?', $subquery1)
->addWhere('e.id IN ?', $subquery2);
return $query->execute();
However this is gives me an error on bound params.
What is the correct ways of constructing such subqueries?
NOTE that if I dont bind the params in the subqueries it works fine.
$nestedQuery = " id IN (SELECT sea.entry_id from table sea where sea.form_element_id = ? and sea.answer = ?) "
. " and id IN (SELECT sea2.entry_id from table sea2 where sea2.form_element_id = ? and sea2.answer = ?)";
return $this->findBySql($nestedQuery, array($param1, $param2, $param3, $param4));
That obviously returns a doctrine collection but you can do getFirst or loop through the returned objects or even use the Hydrator to get an array!

2 join conditions codeigniter giving error

I have 2 tables - for orders and for documents for these orders. I want to show all orders from first table and if there are documents for these orders, to show date of documents(I take date from table documents).
I'm trying to make 2 join conditions because in table documents if I only join on idOrder, there are more than 1 row and I have to join on documents.name to be same as $this->uri->segment(3).
But I'm using the following code and it gives me error. Could I use 2 join conditions in this way:
My model is:
<?php
public function get_all_orders($user_id){
$this->db->select('ordersheader.*, customer.name as customerName,documents.date_make');
$this->db->from('ordersheader');
$this->db->join('customer', 'ordersheader.idCustomer = customer.idCustomer');
$this->db->join('documents', 'ordersheader.idOrder = documents.idOrder','left');
$this->db->join('documents as D', 'D.name="declaration"','left');
$this->db->where('ordersheader.user_id', $user_id);
$query = $this->db->get();
return $query->result_array();
}
Edited: I found solution. But it's written in pure sql, how to write it with Codeingiter syntax? My new working code is:
<?php
$query=("SELECT ordersheader.*, customer.name as customerName,documents.date_make,documents.deactivated_at
FROM ordersheader JOIN customer ON ordersheader.idCustomer = customer.idCustomer
LEFT JOIN documents
ON ordersheader.idOrder = documents.idOrder AND documents.name = '".$document."'
WHERE ordersheader.user_id = '".$user_id."' ");
$result = $this->db->query($query);
return $result->result_array();
This is wrong in your query
$this->db->join('documents as D', 'D.name="declaration"','left');
you can compare column using where clause
public function get_all_orders($user_id){
$this->db->select('ordersheader.*, customer.name as customerName,documents.date_make');
$this->db->from('ordersheader');
$this->db->join('customer', 'ordersheader.idCustomer = customer.idCustomer');
$this->db->join('documents', 'ordersheader.idOrder = documents.idOrder','left');
// $this->db->join('documents as D', 'D.name="declaration"','left'); / comment this line
$this->db->where('documents.name', 'declaration');
$this->db->where('ordersheader.user_id', $user_id);
$query = $this->db->get();
return $query->result_array();
}

Where by month in codeigniter

I have this code
$where = array('MONTH(c.cashDate)' => 'MONTH(NOW())');
$data['dataCash'] = $this->cash->cashList($where);
but it doesn't work, its create query like this
SELECT `c`.`cashId`, `c`.`cashDescription`, `c`.`cashDate`, `c`.`cashCategory`, `a`.`category`, `c`.`cashValue`, `t`.`typeid`, `t`.`type` FROM (`cash` c) LEFT JOIN `cashCategory` a ON `c`.`cashCategory` = `a`.`categoryId` LEFT JOIN `type` t ON `a`.`type` = `t`.`typeid` WHERE MONTH(c.cashDatee) = 'MONTH(NOW())' ORDER BY `c`.`cashDate` desc
when I try with phpmyadmin, it doesnt have a row
but when I remove ' from MONTH(NOW()) like this
SELECT `c`.`cashId`, `c`.`cashDescription`, `c`.`cashDate`, `c`.`cashCategory`, `a`.`category`, `c`.`cashValue`, `t`.`typeid`, `t`.`type` FROM (`cash` c) LEFT JOIN `cashCategory` a ON `c`.`cashCategory` = `a`.`categoryId` LEFT JOIN `type` t ON `a`.`type` = `t`.`typeid` WHERE MONTH(c.cashDatee) = MONTH(NOW()) ORDER BY `c`.`cashDate` desc
it works, how I call func in controller?
when you do this, it wont work
$where = array('MONTH(c.cashDate)' => MONTH(NOW()));
Just update your $where condition
$where = array('MONTH(c.cashDate)' => 'MONTH(NOW())');
into
$where = 'MONTH(c.cashDate) = MONTH(NOW())';

display results on query basis in Codeigniter with Pagination

I have a table of products. I need to display all the products. I am fetching results on different conditions.
create table `products` (
`id` double ,
`category_id` double ,
`subcategory_id` double ,
`product_name` varchar (765),
`product_description` varchar (765),
`product_viewed` varchar (765),
`sale_wanted` tinyint (2),
`added_date` datetime ,
`updated_date` datetime ,
);
I need to diplay the results like this
1. The latest products (use of added date)
2. Most Wanted (Sorting by sale_wanted 1 for sale , 2 for wanted)
3. Most Viewed (Sorting by product_viewed)
4. Sorting by Specific Subcategory
All the results should display with pagination. This is all right if i first get the result. But if i walk with pagination links all the condition data is lost and the query fetches the results without any condition. How can i manage This situation. Please i dont need Code i need hints and suggestions. The other thing is that i am using Codeigniter's pagination class.
EDITED
Here is my Model Method i am using
public function getProductsList($per_page=5,$page=0)
{
$info = $this->input->post();
if(isset($info['type']))
{
$type = $info['type'];
if($type == 'most_wanted'){
$where = " AND sale_wanted = 1";
$order_by = " ORDER BY ldc.added_date desc";
}else if($type == 'most_viewed'){
$where = " ";
$order_by = " ORDER BY ldc.product_viewed desc";
}else{
$where = " ";
$order_by = " ORDER BY ldc.added_date desc";
}
}else if(isset($info['sale_wanted']) AND isset($info['subcategory_id'])){
$sale_wanted = $info['sale_wanted'];
$subcategory_id = $info['subcategory_id'];
$where = " AND sale_wanted = $sale_wanted AND ldc.subcategory_id = $subcategory_id";
$order_by = " ORDER BY ldc.added_date desc";
}else if(isset($info['keyword'])){
$keyword = $info['keyword'];
$search_type = $info['search_type'];
$where = " AND ldc.$search_type like '$keyword%'";
$order_by = " ";
}else{
$where = " ";
$order_by = " ";
}
$num = 0;
if($page != 0){
$num = ($page * $per_page) - $per_page;
}
$sql_query = "
SELECT
ldc.id,
ldc.product_name,
ldc.product_viewed,
DATE_FORMAT(ldc.added_date, '%m/%d/%Y') as added_date,
ifnull(dc.name,'Unknown') as category,
dpi.product_image
FROM default_products AS ldc
LEFT JOIN default_manufacturers as dm ON dm.id = ldc.manufacturer
LEFT JOIN default_category as dc ON dc.category_id = ldc.category_id
LEFT JOIN ((select product_id , product_image from default_product_images group by product_id) as dpi)
ON dpi.product_id = ldc.id
WHERE approved = 1
$where
$order_by
LIMIT $num,$per_page
";
$query = $this->db->query($sql_query);
return $query->result();
}
i would highly recommend these two Free tutorials on codeigniter pagination -
video tutorials, working sample code ( might need to update code to CI 2.1 ), and even some helpful info in the comments.
CodeIgniter from Scratch: Displaying & Sorting Tabular Data
http://net.tutsplus.com/tutorials/php/codeigniter-from-scratch-displaying-sorting-tabular-data/
CodeIgniter from Scratch: Search Results without Query Strings
http://net.tutsplus.com/tutorials/php/codeigniter-from-scratch-search-results-without-query-strings-2/

Resources