how to optimize a long query mysql - mysql

How to optimze this query mysql :
SELECT * FROM rooms WHERE caption LIKE #query OR owner LIKE #query AND roomtype = 'private' ORDER BY users_now DESC LIMIT 50
This is my code:
internal ServerMessage SerializeSearchResults(string SearchQuery)
{
DataTable Data = new DataTable();
using (IQueryAdapter dbClient = PlusEnvironment.GetDatabaseManager().getQueryreactor())
{
if (SearchQuery.Length > 0)
{
if (SearchQuery.ToLower().StartsWith("owner:"))
{
dbClient.setQuery("SELECT * FROM rooms WHERE owner = #query AND roomtype = 'private' ORDER BY users_now DESC LIMIT 50");
dbClient.addParameter("query", SearchQuery.Remove(0, 6));
}
else
{
dbClient.setQuery("SELECT * FROM rooms WHERE caption LIKE #query OR owner LIKE #query AND roomtype = 'private' ORDER BY users_now DESC LIMIT 50");
dbClient.addParameter("query", "%" + SearchQuery + "%");
}
Data = dbClient.getTable();
}
}
List<RoomData> Results = new List<RoomData>();
if (Data != null)
{
foreach (DataRow Row in Data.Rows)
{
RoomData RData = PlusEnvironment.GetGame().GetRoomManager().FetchRoomData(Convert.ToUInt32(Row["id"]), Row);
Results.Add(RData);
}
}

The best way to optimize the performance of the query is to add indexes to the fields that you are using more frequently in your where clauses. For example, in MySQL you can add an index like this:
ALTER TABLE `rooms` ADD INDEX `owner` (`owner`)

The query doesn't look particularly complicate so you might try adding an index by roomtype and users_now to speed up SELECT.
CREATE INDEX index_name ON rooms (roomtype ASC, users_now DESC)
Also try to limit the usage of LIKE in a query as it severely affects performance.

Related

i can not make aritmetic operation inside stored procedure mysql

there is an in parameter as page. all i want to do is expel 1 from it and multiply by 10. but it gives me an error every time.
IF !a THEN
SELECT *
from entry
WHERE topic_foreign_id = (
select topic_id
from topic
where topic_name = topicName
)
ORDER BY entry_time ASC
LIMIT 10 OFFSET page;
ELSE
SELECT *
from entry
WHERE topic_foreign_id = (
select topic_id
from topic
where topic_name = topicName
)
ORDER BY entry_time ASC;
END IF
this lines of code works great but when i want to make an aritmetic operation in first SQL query myAdmin throws an error everytime.
SELECT *
from entry
WHERE topic_foreign_id = (
select topic_id
from topic
where topic_name = topicName
)
ORDER BY entry_time ASC
LIMIT 10 OFFSET 10 * ( page - 1); //throws error
--- EDITED ---
LIMIT doesn't seem to like calculations. Try using a variable and use that value in your stored procedure
DECLARE v_page_offset INT DEFAULT 0;
SET v_page_offset = 10*(page-1);
Then later
LIMIT 10 OFFSET v_page_offset;

MySQL generate random product list based on budget?

I'm tinkering with a function to enable users to specify a budget, and have them receive a list of randomly picked products that add up as best as possible to their specified budget.
As it stands now, I'm trying to do this with PHP but it tends to slow down when there is a huge product list.
Is this at all possible with just a MySQL query?
Edit:
My PHP "implementation":
$budget = 100;
$spent = 0;
$finished = false;
while(!$finished) {
$getRandomProduct = mysql_query('SELECT `id`, `price` FROM `products` WHERE `price` <= "'.($budget-$spent).'" ORDER BY RAND() LIMIT 1');
if(mysql_num_rows($getRandomProduct)) {
$randomProduct = mysql_fetch_assoc($getRandomProduct);
$productList[] = $randomProduct['id'];
$spent += $randomProduct['price'];
} else {
$finished = true;
}
}
The performance and the "randomness" of the result set can be further improved if you first define how many products to include.
$min = 10;
$max = 20;
$total = rand($min,$max);
The algorithm is based on the following:
In a collection of n positive numbers that sum up to S, at least one of them will be less than S divided by n (S/n)
Steps:
Select a product randomly where price < BUDGET /TOTAL. Get its price, lets say X.
Select a product randomly where price < (BUDGET - X)/(TOTAL - 1). Get its price, assume Y.
Select a product randomly where price < (BUDGET - X - Y)/(TOTAL - 2).
Repeat this and get (TOTAL - 1) products. For the last product, select one where price = remaining price. (or price <= remaining price and order by price desc and hopefully you could get close enough).
$budget = 100;
$spent = 0;
$finished = false;
for($i = 0; $i < $total - 1; $i++) {
$getRandomProduct = mysql_query('SELECT `id`, `price` FROM `products` WHERE `price` <= "'.(($budget-$spent)/($total - $i)).'" ORDER BY RAND() LIMIT 1');
if(mysql_num_rows($getRandomProduct)) {
$randomProduct = mysql_fetch_assoc($getRandomProduct);
$productList[] = $randomProduct['id'];
$spent += $randomProduct['price'];
} else {
break;
}
}
$getRandomProduct = mysql_query('SELECT `id`, `price` FROM `products` WHERE `price` <= "'.($budget-$spent).'" ORDER BY `price` DESC LIMIT 1');
$productList[] = $randomProduct['id'];
This improves:
The query performance, the condition is more strict
The result set is more random, as previous you could easily select the 1st product close to the budge and limit the budget of the others
References:
My answer using the same algorithm for another question

Last four items of the websql database

This is my function for all the data from my database. I only want the last four data out of the database.
function spelerWeergeven()
{
db.transaction(function(tx)
{
tx.executeSql('SELECT * FROM speler', [], function (tx, results)
{
var len = results.rows.length, i;
if(len > 0)
{
$('#spelerTabel').replaceWith('<table id="spelerTabel"><tr><th>Spelers</th></tr></table>');
$('#spelerTabel').hide();
for(var i = 0; i< len; i++)
{
$('#spelerTabel tr:last').after('<tr><td>'+results.rows.item(i).naam+'</td></tr>');
}
$('#spelerTabel').show('slow');
}
}, null);
}
);
}
Does anybody know the answer?
SELECT * FROM `speler` ORDER BY `id` DESC LIMIT 4;
This should work
SELECT *
FROM `speler`
ORDER BY `id` DESC
LIMIT 4;
(The backticks (`) are used to prevent SQL from reading the words between them as a keyword. It's a good thing to keep that in mind, since there are many, many keywords in SQL.)
Edit:
Since you have created a table called speler with the columns id (which is the primary key) and naam using the query CREATE TABLE IF NOT EXISTS speler (id INTEGER PRIMARY KEY, naam), we know your primary key column is id.
PS: It's a good thing to let table names start with capital letter (Speler), by convention.
This will do it server side:
SELECT TOP 4 * FROM
speler
ORDER BY id DESC
Also pretty clean using Linq:
//dc would be a linq datacontext
string cmd = #"SELECT TOP 4 * from speler order by id DESC";
IEnumerable<speler> fourItems = dc.ExecuteQuery<speler>(cmd);

How to do a count(*) in Hibernate?

How can I count the records in a MySQL table in Hibernate? I tried the following HQL, but it does not work.
SELECT COUNT(*) FROM MEMBERS WHERE `username` =:USERNAME OR `email` =:EMAIL
It is used in the following method:
public boolean checkInfos() {
Session newSession = NewHibernateUtil.getSessionFactory().openSession();
int count = (Integer) newSession.createSQLQuery("SELECT COUNT(*) FROM MEMBERS WHERE `username` ='admin' OR `email` ='admin'").uniqueResult();
if (count >= 1) {
return false;
} else {
return true;
}
}
I guess you need that
Query q = newSession.createSQLQuery("SELECT COUNT(*) FROM MEMBERS WHERE username = ? OR email =?");
q.setParameter( 1, "your username");
q.setParameter(2, "your email");
Select count(*) returns a Long, not an Integer.
One more thing: The backticks, which you are using, are not accepted by every database.
By the way, you can use count(*) also in HQL. This means, you can use createQuery instead of createSQLQuery. An advantage of HQL is, it is portable from one database to another, which is not always the case for SQL statements.
You also can achieve this by using criteria also.
private Number getCount(){
Criteria criteria = session.createCriteria(Members.class);
criteria.add(Restrictions.or(Restrictions.eq("username", "admin"), Restrictions.eq("email","admin")));
criteria.setProjection(Projections.rowCount());
return (Number) criteria.list();
}

Dynamic values inside the mysql query

I am trying to get result using below query, idRegion is recorded in database as 1,2,3,4 for each franchisee, so what I want is to display all franchisees with idRegion 2. I am getting idRegion via $_Get. this display only first digit before coma, I think so it should ready whole string 1,2,3,4 ? When I am working with static values that works?
$colname_franchisee = "-1";
if (isset($_GET['id'])) {
$colname_franchisee = $_GET['id'];
}
$query_franchisee = sprintf("SELECT * FROM franchise WHERE stiShowInLinks = 'Y' AND idRegion LIKE '%s%' ORDER BY stiName ASC", $colname_franchisee);
This should work although I do not like your database design:
$query_franchisee = sprintf("
SELECT *
FROM franchise
WHERE
stiShowInLinks = 'Y' AND (
idRegion = '%d' OR
idRegion LIKE '%d,%%' OR
idRegion LIKE '%%,%d' OR
idRegion LIKE '%%,%d,%%'
)
ORDER BY stiName ASC
",
$colname_franchisee,
$colname_franchisee,
$colname_franchisee,
$colname_franchisee
);
The sprintf function treats the % character as a format specifier and treats at the next few characters in a special way. In order to use the % character literally, you must use %%. So after sprintf, your query becomes:
idRegion = '1234' OR
idRegion LIKE '1234,%' OR
idRegion LIKE '%,1234' OR
idRegion LIKE '%,1234,%'
$colname_franchisee = "-1";
if (isset($_GET['id'])) {
$cf = intval($_GET['id']); only if id integer.
}
$query_franchisee = "SELECT * FROM franchise
WHERE stiShowInLinks = 'Y'
AND idRegion LIKE '%cf%'
ORDER BY stiName ASC", $cf);