What's the logic?
SELECT field1, field2,...fieldN table_name1, table_name2...
ORDER BY field1, [field2...] [ASC [DESC]]
So if I have ORDER BY field1, field2 :
(Please let me know if i'm wrong) it will sort results by field1 and if field1 has the same values in a couple rows (field1[235]=field1[236]) only in then ORDER BY field2 kicks in. Right?
Indeed.
That is how it works.
But why do I see so many of these questions here on SO? What happened to experimenting, trying stuff out, playing, etc?
Related
I am developing a web application that has a listbox with thousands of records from a MySQL database ('Table1').
I have a quick search field that searches all fields with the OR
operator (value: aaaa).
I have a dialog box that allows filtering by all fields with the AND
operator (values: xxx, yyy, zzz).
The idea is to create a query that contains both, the filtered values and the search value.
I have created a subquery on a FROM clause like this:
SELECT b.*
FROM
( SELECT *
FROM Table1
WHERE Field1 LIKE '%xxx%'
AND Field2 LIKE '%yyy%'
AND Field3 LIKE '%zzz%'
) b
WHERE b.Field1 LIKE '%aaaa%'
OR b.Field2 LIKE '%aaaa%'
OR b.Field3 LIKE '%aaaa%'
After running the subquery it seems to me that the performance is not optimal.
Would it be possible to improve the query in some way to optimize the performance (and lower the response time)?
Thank you very much.
Wardiam
Update:
It seems to me that it would be more correct to use a Common Table Expression (CTE). I have used this CTE expression:
WITH CTE_Expression AS
(SELECT *
FROM Table1
WHERE Field1 LIKE '%xxx%'
AND Field2 LIKE '%yyy%'
AND Field3 LIKE '%zzz%'
)
SELECT b.*
FROM CTE_Expression b
WHERE b.Field1 LIKE '%aaaa%'
OR b.Field2 LIKE '%aaaa%'
OR b.Field3 LIKE '%aaaa%'
What do you think?.
Found a similar issue:
Mysql Improve Search Performance with wildcards (%%)
No, because MySQL will not be able to utilize the index when you have
a leading wildcard. If you changed your LIKE to 'aaaa%', then it would
be able to use the index.
If you want to check if indices are being utilized, check the execution plan with EXPLAIN:
https://dev.mysql.com/doc/refman/8.0/en/using-explain.html
Or try using the MYSQL Full-Text Index MATCH()/AGAINST(). Here are some articles about:
https://severalnines.com/database-blog/full-text-searches-mysql-good-bad-and-ugly
https://www.w3resource.com/mysql/mysql-full-text-search-functions.php
Edit:
After some investigation, I came to the conclusion that there is no way a leading wildcard can utilize the Table index
Wildcard search in MySQL full-text search
https://blog.monyog.com/problem-queries-are-killing-your-database-performance/
Before running a REGEXP_REPLACE on a big table, I want to preview the results, so I want to copy the 'before' and 'after' of the modified field to another table so I can audit.
What's the best way to do this?
Something like
INSERT INTO table2 (before, after)
SELECT field1, REGEXP_REPLACE(field1,'foo','bar')
FROM table1
WHERE condition
(MariaDB)
If this were my project I'd do these things.
First. Just do this and eyeball the results.
SELECT COUNT(*), field1, REGEXP_REPLACE(field1,'foo','bar')
FROM table1
WHERE field1 <> REGEXP_REPLACE(field1,'foo','bar')
GROUP BY field1, REGEXP_REPLACE(field1,'foo','bar')
ORDER BY COUNT(*), field1
That will show you the least frequent values first so you can see the one-off problems caused by your replace first. No need to create a table.
Second, I'd eyeball the values that DIDN'T change with this, changing the WHERE clause from <> to =.
SELECT COUNT(*), field1
FROM table1
WHERE field1 = REGEXP_REPLACE(field1,'foo','bar')
GROUP BY field1
ORDER BY COUNT(*), field1
Maybe some stuff didn't change that should have.
Edit SQL can get a little verbose. If you're fiddling around with some complex conversion functions you might try creating a view. Something like this:
CREATE OR REPLACE VIEW testview AS
SELECT field1,
REGEXP_REPLACE(field1,'foo','bar') changed
FROM table1;
Then you can do
SELECT COUNT(*), field1, changed
FROM testview
WHERE field1 <> changed
GROUP BY field1, changed
ORDER BY COUNT(*), field1;
And similar queries. If you must change your replace function, you can edit the view definition and do the CREATE OR REPLACE again.
I want to use different conditions depending on a certain field value.
If for example the value of field1='abc' then field2 should be '123' else field3 should be '456'. My query is much more complex, but the question is whether I could use different conditinons depending on a field value.
Something like that:
SELECT * FROM table
WHERE
CASE table.field1='abc'
THEN table.field2='123'
ELSE table.field3='456'
I have a solution for my problem, but it goes with 3 subqueries which takes a lot of time to respond.
If for example the value of field1='abc' then field2 should be '123'
else field3 should be '456'
You don't really need a CASE statement here. Rather use different combination of condition like.
WHERE (field1 = 'abc' and field2 = '123')
OR (field1 != 'abc' and field3 = '456')
suppose I do this:
SELECT * FROM table WHERE field2 = '2019#162440' OR field2 LIKE '%%2019#%%';
In this case, it will try to execute the matching of BOTH field2 = '2019#162440'and field2 LIKE '%%2019#%%' conditions (ie, it will search for rows matching those conditions hence it takes some more computation power to try to find rows matching both condition even if it already found a row matching field2 = '2019#162440')
Is there a way to instruct mysql by reforming the query to ONLY try to execute field2 LIKE '%%2019#%%' if the condition field2 = '2019#162440' does not match anything so that the query becomes more efficient
IE. I essentially want mysql to only try to find rows matching field2 LIKE '%%2019#%%' only if no rows match field2 = '2019#162440'. If a row that matches field2 = '2019#162440' is found, do NOT try to match field2 LIKE '%%2019#%%'
Also, no subqueries
Let me start by stating that I am not an expert in MySQL. It is not nearly as optimized as some other DBMSes, so the following query might not actually reduce your execution time. But it's worth a shot...
If field2 is indexed, this might be a really fast solution:
-- Get results where field2 = '2019#162440'
SELECT *
FROM table
WHERE field2 = '2019#162440'
-- Append...
UNION
-- Get results where field2 LIKE '%%2019#%%' but only
-- if there are no rows where field2 = '2019#162440'
SELECT *
FROM table
WHERE NOT EXISTS(
SELECT *
FROM table
WHERE field2 = '2019#162440'
)
AND field2 LIKE '%%2019#%%'
You are going to run your fastest query and select all results. Then, append the second, slower query which contains an EXISTS. The EXISTS clause will return true if the subquery contains any rows, which should short-circuit the entire second query and prevent it from runnning (thus appending 0 rows). If the first query returns 0 rows, however, then the second query will kick in and run the slower LIKE comparisons.
The best I can do is use the FOUND_ROWS() function along with a UNION:
SELECT *
FROM t
WHERE field2 = '2019#162440'
UNION ALL
SELECT *
FROM t
WHERE FOUND_ROWS() = 0
AND field2 LIKE '%%2019#%%'
SQL Fiddle Demo
Using laravel/fluent query builder, I'm trying to cause a constant field value to pass through for a union(ed) selection that is subsequently ordered . I haven't found the recipe to do the following with fluent. The unions are easy, but how do you get the field constant to work?
Imagine two simple tables (omitted) and a union select:
select field1, field2, 'type1' as field3 from table1
UNION
select field1, field2, 'type2' as field3 from table2
ORDER BY field2
The best answer I've come up with so far, is to use a DB::query with a query string I manufacture myself. Laravel/fluent does not seem ready to handle this case, given the test cases I've tried. Using RAW for a select works great, until you try to order the pair of selected table queries.
SELECT field1, field2 FROM
(
SELECT fld1A as field1, 'FOO' as field2 from table1
UNION ALL
SELECT fld2A as field1, 'BAR' as field2 from table2
)
temp_table order by somefield
Using Laravel 4, and using GROUP BY, rather than ORDER BY I believe you can do something like:
$t1 = DB::table('table1')
->select('field1',DB::raw("'FOO' as field2"))
->groupBy('field2');
$t2 = DB::table('table2')
->select('field1',DB::raw("'BAR' as field2"))
->groupBy('field2');
$result = $t1->union($t2)->get();
I found that $t1 in this case can be an instance of Illuminate\Database\Query\Builder or Illuminate\Database\Eloquent\Builder, but the union argument ($t2) must be of type Illuminate\Database\Query\Builder.
This means that you may use eager loading with something like:
$t1 = MyTableModel::with('table3')->select...
This way, probably:
$users = DB::table('users')
->select(DB::raw("'FOO' as field2"))
->get();