How to reduce Mysql execution Time? - php

I'm using Mysql 5.5.16. I've a query where i combine 3 queries using union opeartor... Each query contains more than 10000 records.
My Query looks like...
$search_qry1 = " (SELECT PC_name as name FROM profile_category_tbl WHERE PC_status=1 and PC_parentid!=0 and (";
$search_qry2 = " (SELECT PROFKEY_name as name FROM profile_keywords_tbl WHERE PROFKEY_status=1 and (";
$search_qry3 = " (SELECT COM_name as name FROM ".$C."_company_profile_tbl WHERE COM_status=1 and (";
$order_by = "ORDER BY";
$word_length = explode(" ", $my_data);
for($i=0; $i <= count($word_length) - 1; $i++) {
$dt = $word_length[$i];
if ($dt) {
if ($i == 0) {
$or="";
}
else {
$or="OR";
}
$search_qry1 .= " $or regex_replace('[^a-zA-Z0-9\-]','',remove_specialCharacter(PC_name)) LIKE '%$dt%' ";
$search_qry2 .= " $or regex_replace('[^a-zA-Z0-9\-]','',remove_specialCharacter(PROFKEY_name)) LIKE '%$dt%' ";
$search_qry3 .= " $or regex_replace('[^a-zA-Z0-9\-]','',remove_specialCharacter(COM_name)) LIKE '%$dt%' ";
$order_by .= " IF(name LIKE '%$dt%',1,0) ";
}
if ($i == count($word_length) - 1) {
$search_qry1 .= ")";
$search_qry2 .= ")";
$search_qry3 .= ")";
}
if ($i != count($word_length) - 1) {
$order_by .= "+ ";
}
}
$search_qry1 .= " GROUP BY PC_name )";
$search_qry2 .= " GROUP BY PROFKEY_name )";
$search_qry3 .= " GROUP BY COM_name )";
$search_qry = "select name from ( $search_qry1 UNION ALL $search_qry2 UNION ALL $search_qry3 )a $order_by desc LIMIT 0,25";
It works perfectly... but it takes the time to execute it - more than 4 secs... for each search.... how possible to reduce its execution time?.... If anyone know an idea about this please let me know....
Actually I run this query for auto-complete search. If type "Rest" in search box, then
The Output Should be,
Family Restaurants
Everest Park
Fast Food Restaurants
Everest Park Residency
Fish Restaurant
Everest Power Solution
Fish Restaurants
Thanks in Advance,
Jeni

You are using regex_replace and like "%foobar%",
that actually slows down your query significat, since mySql has to do a fulltext search and the regex operation on every single row. Maybe it's faster if you do these operations after you fetched your results, using php instead of mysql.

The main problem is that you're doing a full scan of each table to check the like '%$dt%' condition. No matter which indices you have on the table, none of them will be used.
But if you post the final SQL sentence and what are you trying to do maybe we could help.

Related

mysql dynamic queries without clause where

In the following example there is a base query. Other parameters can be dynamically added to complete the query.
However, my base query has no clause WHERE.
What is the best way to deal with it.
If I use in the base query, for example, WHERE 1 = 1, it seems to solve, but I have some doubts that is a correct solution.
$myQuery = "SELECT fr.oranges, fr.aplles, fr.bananas,
FROM fruits fr
LEFT JOIN countrys ct ON fr.id_fruit = ct.id_fruit";
if(!empty($countrys){
$myQuery .= " AND countrys = ? ";
}
if(!empty($sellers){
$myQuery .= " AND seller = ? ";
}
$myQuery .=" GROUP BY fr.id_fruit ORDER BY fr.fruit ASC";
Edited: I fixed a writing gap from $empty to empty.
The WHERE 1=1 is a simplistic hack that works well because it simplifies your code. There is a great post here which explains the performance implications of WHERE 1=1. The general consensus is it will have no effect on performance.
Also, slight note ($empty) is probably not a function you've defined. I think you want empty(). You could write it like this:
$myQuery = "SELECT fr.oranges, fr.aplles, fr.bananas,
FROM fruits fr
LEFT JOIN countrys ct ON fr.id_fruit = ct.id_fruit";
$where = [];
if(!empty($countrys){
$where[] = "countrys = ?";
}
if(!empty($sellers){
$where[] = "seller = ?";
}
if (!empty($where)) {
$myQuery .= " WHERE " . implode(" AND ", $where);
}
$myQuery .= " GROUP BY fr.id_fruit ORDER BY fr.fruit ASC";
You can use an array to control your SQL like this:
$where = [];
if(!$empty($countrys){
$where[] = " countrys = ? ";
}
if(!$empty($sellers){
$where[] = " seller = ? ";
}
if(count($where) > 0) {
$myQuery .= " WHERE ".implode('AND', $where);
}

Where clause stopped working

I have this code that (without the WHERE, was working) How do I get it to work with the WHERE clause ?
I just need it to only list lines that is current and max 2 years ahead.
$SQL = "SELECT ";
$SQL .= "SUM(Bookings.Spots) as SUMSPOT, Trips.ID, Bookings.FK_ID, Trips.MaxSpots, ";
$SQL .= "Trips.Tripnr, Trips.StartDate, Trips.EndDate, Trips.StartLocation, ";
$SQL .= "Trips.DestinationDK, Trips.PricePerSpot ";
$SQL .= "FROM Trips WHERE Trips.EndDate >= NOW() AND Trips.EndDate < DATE_ADD(NOW(), INTERVAL 2 YEAR) ";
$SQL .= "LEFT JOIN Bookings on Bookings.FK_ID = Trips.ID ";
$SQL .= "GROUP BY Trips.ID, Bookings.FK_ID ORDER BY Trips.StartDate ASC ";
You need to add the WHERE clause after the LEFT JOIN and before the GROUP tag.
You can check the documentation here for more answers as to where you can put which keyword.

Setting up SQL queries with multiple parameters

I need to set up a SQL query with multiple parameters that are being pulled from the URL. So far I can only get it to work with the there is only one item in the URL.
My default query to pull in all the content
$sql = "SELECT ";
$sql .= "* ";
$sql .= "FROM ";
$sql .= "cms_site_content ";
$sql .= "WHERE ";
$sql .= "1";
I then check if anything was passed through the URL and retrieve it.
if (isset($_GET["d"])) {
$d=$_GET["d"];
Inside the if statement, I break the values passed as "d" into separate items
$newD = explode(',',$d);
$countD = count($newD);
foreach($newD as $discipline) {
if ($countD == 1) {
$sql .= " AND";
$sql .= " discipline='".$discipline."'";
}
My problem is getting the SQL to work if there is more than one discipline value. It should read something like this:
SELECT * FROM cms_site_content WHERE 1 AND discipline="value"
however if there's more than one discipline value, it should read:
SELECT * FROM cms_site_content WHERE 1 AND discipline="value OR discipline="value2" OR discipline="value3"
Is there a more efficient way to write this? I can't figure out how to insert the OR into the foreach statement.
Save all discipline values in an array;
$discipline_arr = array();
foreach($newD as $discipline) {
$discipline_arr[] = $discipline;
// by the way, don't forget to escape for sql injection
// mysql_escape_string is the depracated one, u can use that if u have no
// other choice
}
Then in your sql, add them as discipline in ('value1','value2', 'etc ...') condition (that is for strings, for numeric types it would be like discipline in (1,2,3,4, etc)
$sql = " SELECT * FROM cms_site_content WHERE 1 " .
(empty($discipline_arr) ? "" : "and
discipline in ('". implode("','" , $discipline_arr). "') ") ;
Link to escaping
http://tr1.php.net/manual/en/function.mysql-escape-string.php
Assuming the rest of your query is in tact. Simply store all of your discipline values in an array as follows, then feed the $discipline_string to your $sql query:
$discipline_ary = array('option1', 'option2', 'option3');
$discipline_string = "";
for($i=0; $i < count($discipline_ary); $i++){
$discipline_string .= " discipline = '" . $discipline[$i] . "' ";
if($i+1 == count($discipline_ary)){
break;
}else{
$discipline_string .= " OR "
}
}

Search form query with multiple values - PHP / MYSQL

I'm having a little trouble with a search form I've been creating the functionality for. I basically want a form (on whatever page) to go to this page then list the relevant rows from my database. My problem is that the form has both a text field and a select field (for name and categories) and I've been unable to create the functionality for having these two values search the database together.
So heres what I want to happen: When you only type in the name and not the category, it will display from just the name, vise versa for the category and no name; then when both together it only displays rows with both of them in.
Heres what I have so far:
// 2. Create variables to store values
if(!$_GET['search-category'] == "") {
$searchName = $_GET['search-name'];
}
if(!$_GET['search-category'] == "select-your-category") {
$searchCat = $_GET['search-category'];
}
// 2. Create the query for the stored value. Matching it against the name, summary and sub type of my item.
$mainSearch = "SELECT attraction.*, type.type_name, sub_type.sub_type_name ";
$mainSearch .= "FROM attraction ";
$mainSearch .= "INNER JOIN sub_type ON attraction.sub_type = sub_type.sub_type_id ";
$mainSearch .= "INNER JOIN type ON attraction.type = type.type_id ";
$mainSearch .= "WHERE attraction.name LIKE '%" . $searchName . "%' AND (sub_type.sub_type_name LIKE '%" . $searchCat . "%' )";
$mainSearch .= "ORDER BY sub_type_name ASC";
// 2. run query
$result2 = $con->query($mainSearch);
if (!$result2) {
die('Query error: ' . mysqli_error($result2));
}
I'd refactor the code to something like -
foreach( $_GET['filters'] as $fname => $fval ) {
if( !$fval ) continue;
$where[] = "$fname LIKE '%{$fval}%'";
}
You need to include only those inputs that are non-empty in the query. Also you will need to address security issues like escaping inputs etc.
What you can do is that declare a variable called $search_condition and based on whether $searchName or $searchCat is null or not assign value to $search_condition
For e.g.
if (isset($searchName ) || !is_empty($searchName ))
{
$search_condition = "WHERE attraction.name LIKE '%" . $searchName;
}
if (isset($searchCat ) || !is_empty($searchCat ))
{
$search_condition = "sub_type.sub_type_name LIKE '%" . $searchCat . "%'";
}
if ((isset($searchName ) || !is_empty($searchName )) && (isset($searchCat ) || !is_empty($searchCat )))
{
$search_condition = "WHERE attraction.name LIKE '%" . $searchName . "%' AND (sub_type.sub_type_name LIKE '%" . $searchCat . "%' )";
}
Hope this might help you
Thanks
This is a comment, but I want to take advantage of formatting options...
You know, you can rewrite that this way...
// 2. Create the query for the stored value. Matching it against the name, summary and sub type of my item.
$mainSearch = "
SELECT a.*
, t.type_name
, s.sub_type_name
FROM attraction a
JOIN sub_type s
ON a.sub_type = s.sub_type_id
JOIN type t
ON a.type = t.type_id
WHERE a.name LIKE '%$searchName%'
AND s.sub_type_name LIKE '%$searchCat%'
ORDER
BY s.sub_type_name ASC;
";
You can just check that the relevant values aren't empty:
// 2. Create the query for the stored value.
// Matching it against the name, summary and sub type of my item.
$mainSearch = "SELECT attraction.*, type.type_name, sub_type.sub_type_name ";
$mainSearch .= "FROM attraction ";
$mainSearch .= "INNER JOIN sub_type ON attraction.sub_type = sub_type.sub_type_id ";
$mainSearch .= "INNER JOIN type ON attraction.type = type.type_id ";
$mainSearch .= "WHERE ";
if ($searchName) {
$mainSearch .= "attraction.name LIKE '%" . $searchName . "%'";
if ($searchCat) {
$mainSearch .= " AND ";
}
}
if ($searchCat) {
$mainSearch .= "sub_type.sub_type_name LIKE '%" . $searchCat . "%'"
}
$mainSearch .= "ORDER BY sub_type_name ASC";
// Double check that at least one of the search criteria is filled:
if (!$searchName && !$searchCat) {
die("Must supply either name search or category search");
}

removing avoiding duplicates from resultset

I have this query:
$relevantwords = {"one" , "two" , "three" } ;
foreach ($relevantwords as $word)
{
$query .= "SELECT * FROM delhi_items WHERE heading like '%$word%' AND id!={$entry_row['id']} AND visible=1 UNION ALL " ;
}
$query = implode( " " , explode(" " , $query , -3) ) ;
$query .= " ORDER BY time_stamp DESC LIMIT 0, 20 " ;
$result_set = mysql_query($query, $connection);
This causes several duplicates in my resultset. Is there a way to detect and remove these duplicates from the resultset ? I know I should probably try to avoid the duplicates in the first place, but I am unable to figure that out.
Also I tried distinct keyword, it didn't work (because its a loop, the same entry is fetched again and again).
Laslty I am kind of an amateur so please tell me if I am doing something fundamentally uncool with such a long sql query in a for loop.
Thanks
This is not the right way to do this query; don't use UNION ALL with several queries.
Just use one query and use an OR between the relevant WHERE clause parts. It'll select each row just once, regardless of how many bits it matches.
I would try to have one SELECT and no UNION and DISTINCT. It will probably be a faster query:
$relevantwords = {"one" , "two" , "three" } ;
$querycondition = "" ;
foreach ($relevantwords as $word)
{
$querycondition .= " heading LIKE '%$word%' OR"
}
$querycondition = substr($querycondition ,0 ,strlen($querycondition)-2 ) ;
$query = " SELECT * "
. " FROM delhi_items "
. " WHERE ( "
. $querycondition
. " ) "
. " AND id!={$entry_row['id']} "
. " AND visible=1 "
. " ORDER BY time_stamp DESC "
. " LIMIT 0, 20 " ;
$result_set = mysql_query($query, $connection);
Use DISTINCT:
SELECT DISTINCT * FROM ...
UPDATE:
Actually DISTINCT doesn't work since the un-duping would happen before the records are merged with each other in the UNION ALL.
To do what you are trying to do, you want the SELECT DISTINCT * to happen outside the union-ing of all the records.
Do the selecting and union-ing inside a derived table:
SELECT DISTINCT * FROM
(SELECT * FROM TABLE WHERE ...
UNION ALL
SELECT * FROM TABLE WHERE ...
) t
ORDER BY ...

Categories