MySql: variable row max min query? - mysql

I have a MySql table containing stock quotes (stock_symbol, quote_date, open_price, high_price, low_price, close_price) and need to find out various max and min values: Max High/Min Low over 10/20/245/252 days.
I know how to do this using a SELECT query for each period:
SELECT max(high_price), min(low_price) FROM mytable WHERE stock_symbol = 'GOOG' ORDER BY quote_date DESC LIMIT 10;
Can it be done using a single SELECT statement without making the query too intense for the database server? Would a single SELECT statement perform better than multiple SELECT statements?
Any thoughts/help would be much appreciated. Thanks!

Do it preferably in one statement, but the problem is only on the indexes : be sure to have an index on all columns for which you ask the min and the max or that you add in the where clause : hight_price, low_price and stock_symbol.
With indexes, this request will be instantaneous, even for very big tables and without your LIMIT 10
Don't put an ORDER BY in this query : it's useless as the min and max are the same independently of the order you look at the set.
Your query should be simply
SELECT max(high_price), min(low_price) FROM mytable WHERE stock_symbol = 'GOOG'
How to create an index : http://dev.mysql.com/doc/refman/5.0/en/create-index.html

Related

How to Selecting 500 rows to be processed in meantime get the total rows in that table

is there a way to select couple columns using a limit but in mean time get the total count of rows in that table
SELECT col1,col2 FROM table where col3=0 limit 500
just like above. what to add to get the total of rows in the table
thank you
Try this, you only need to use one column in the count
SELECT COUNT(col3) FROM table where col3=0
And here's a reference for more information MySQL COUNT
Note, to keep it simple, you have to run two queries, this one for the count and yours for the records
Your question lacks a precise problem statement.
My understanding of your question is as follows:
All of the following is necessary:
Need to get every row from the table, such that col3=0.
Need to get the total number of rows in the table (whether they satisfy col3=0 or not).
Need to limit your result set to columns col1, col2, and have at most 500 rows.
Need to execute a single query, rather than two separate queries.
If this is correct interpretation of your question, then I would propose the following solution:
SELECT col1,col2, (SELECT COUNT(*) FROM table) AS total_rows FROM table where col3=0 limit 500
Such query would produce result where at most 500 rows from your table satisfy the condition col3=0 are present alongside total_rows, which tells the number of all the rows in the table.
Example CSV of the result:
clo1,col2,total_rows
a,b,1000
c,d,1000
d,e,1000
according to found_rows()
The SQL_CALC_FOUND_ROWS query modifier and accompanying FOUND_ROWS() function are deprecated as of MySQL 8.0.17; expect them to be removed in a future version of MySQL. As a replacement, considering executing your query with LIMIT, and then a second query with COUNT(*) and without LIMIT to determine whether there are additional rows
instead of these queries:
SELECT SQL_CALC_FOUND_ROWS * FROM tbl_name WHERE id > 100 LIMIT 10;
SELECT FOUND_ROWS();
Use these queries instead:
SELECT * FROM tbl_name WHERE id > 100 LIMIT 10;
SELECT COUNT(*) FROM tbl_name WHERE id > 100;
COUNT(*) is subject to certain optimizations. SQL_CALC_FOUND_ROWS causes some optimizations to be disabled.
you can check these questions
how-to-get-number-of-rows
mysql-what-is-the-row-count-information-function-for-select

Optimizing query with LIMIT mysql

I have a table, lets call it mytable, which holds huge amount of data that I need to query based on some column values of types varchar and datetime (none of these columns have indexing on them and I cannot use primary key for this query).
I need to fetch the data with pagination, for which I am using variables varLimit and varOffset. Now what I have noticed after much experimentation is that though LIMIT varLimit optimizes a query when result count is high, it severely reduces performance when it is greater than the result count. If the query returns 0 rows, with LIMIT 20 applied it takes 30 more seconds than it does with the LIMIT removed!
Here's my query
SELECT `data`
FROM mytable
WHERE (conditions...)
ORDER BY `heure` desc LIMIT varLimit OFFSET varOffset;
To optimize this, I have to first re-calculate varLimit to set it to the minimum value between result count and itself (varLimit = 20 but if query returns 10 rows, it should set varLimit = 10. The final code becomes:
SELECT COUNT(*) INTO varCount
FROM mytable
WHERE (conditions...);
SELECT LEAST(varLimit, varCount - varOffset) INTO varLimit; -- Assume varOffset <= varCount
SELECT `data`
FROM mytable
WHERE (conditions...)
ORDER BY `heure` desc LIMIT varLimit OFFSET varOffset;
Is there any way to do it in a single query, or a better way to achieve the same?
Unfortunately you cannot use variables in LIMIT and OFFSET clauses. They must be constants, so you must do this limit/offset computation either in application code or by creating a MySQL "prepared statement" with string concatenation.

MySQL split table query using varchar column

I have a table in MySQL which I want to query parallel by executing multiple select statements that select
non-overlapping equal parts from the table, like:
1. select * from mytable where col between 1 and 1000
2. select * from mytable where col between 1001 and 2000
...
The problem is that the col in my case is varchar. How can I split the query in this case?
In Oracle we can operate with NTILE in combination with rowids. But I didn't find a similar approach in case of MySQL.
That's why my thinking is to hash the col value and mod it by the number of equal parts I want to have.
Or instead of hashing, dynamically generated rownums could be used.
What would be an optimal solution considering that the table big (xxxM rows) and I want to avoid full table
scans for each of the queries?
You can use limit for the purpose of paging, so you will have:
1. select * from mytable limit 0, 1000
2. select * from mytable limit 1000, 1000
you can use casting for varchar column to integer like this cast(col as int)
Regards
Tushar
Without scanning fulltable, it will produce results
SELECT * FROM mytable
ORDER BY ID
OFFSET 0 ROWS
FETCH NEXT 100 ROWS ONLY

MySQL: Select minimum values of dataset without using subquery

How can I get the minimum values! (plural) from a table without using a subquery? The table contains following data (sorry four the mouse):
As you can see, I always want to select the minimum values. If there are the same values (table 2 & 3) the query shall give all rows, because there is no minimum. I'm using MySQL. I don't want to use a subquery if possible because of performance reasons. A min(value) and group by id doesn't work either, because of the unique ids.
Thanks in advance
ninsky
As far as I know, this cannot be done without a subquery in MySQL. For example:
select *
from YourTable
where value =
(
select min(value)
from YourTable
)
if you do not trust MySQL in performance you can split query proposed by Andomar to 2 atomic subquery

How to optimize a MySQL query so that a selected value in a WHERE clause is only computed once?

I need to randomly select, in an efficient way, 10 rows from my table.
I found out that the following works nicely (after the query, I just select 10 random elements in PHP from the 10 to 30 I get from the query):
SELECT * FROM product WHERE RAND() <= (SELECT 20 / COUNT(*) FROM product)
However, the subquery, though relatively cheap, is computed for every row in the table. How can I prevent that? With a variable? A join?
Thanks!
A variable would do it. Something like this:
SELECT #myvar := (SELECT 20 / COUNT(*) FROM product);
SELECT * FROM product WHERE RAND() <= #myvar;
Or, from the MySql math functions doc:
You cannot use a column with RAND()
values in an ORDER BY clause, because
ORDER BY would evaluate the column
multiple times. However, you can
retrieve rows in random order like
this:
mysql> SELECT * FROM tbl_name ORDER BY
> RAND();
ORDER BY RAND() combined with LIMIT is
useful for selecting a random sample
from a set of rows:
mysql> SELECT * FROM table1, table2
> WHERE a=b AND c<d -> ORDER BY RAND()
> LIMIT 1000;
RAND() is not meant to be a perfect
random generator. It is a fast way to
generate random numbers on demand that
is portable between platforms for the
same MySQL version.
Its a highly mysql specific trick but by wrapping it in another subquery MySQL will make it a constant table and compute it only once.
SELECT * FROM product WHERE RAND() &lt= (
select * from ( SELECT 20 / COUNT(*) FROM product ) as const_table
)
SELECT * FROM product ORDER BY RAND() LIMIT 10
Don't use order by rand(). This will result in a table scan. If you have much data at all in your table this will not be efficient at all. First determine how many rows are in the table:
select count(*) from table might work for you, though you should probably cache this value for some time since it can be slow for large datasets.
explain select * from table will give you the db statistics for the table (how many rows the statistics thinks are in the table) This is much faster, however it is less accurate and less accurate still for InnoDB.
once you have the number of rows, you should write some code like:
pseudo code:
String SQL = "SELECT * FROM product WHERE id IN (";
for (int i=0;i<numResults;i++) {
SQL += (int)(Math.rand() * tableRows) + ", ";
}
// trim off last ","
SQL.trim(",");
SQL += ")";
this will give you fast lookup on PK and avoid the table scan.