N1QL Query using index and USE KEYS - couchbase

I need to perform a N1QL query where some of the records can be selected by an indexed attribute and others can be identified by their IDs. I tried to use
SELECT name FROM b WHERE collection in $cList OR meta().id IN $idList
But this returns an error saying there is no index available that matches my query. I can use UNION with 2 separate queries:
SELECT name FROM b WHERE collection in $cList
UNION
SELECT name FROM b USE KEYS $idList
Is that the best way to do this? Or is there some way to combine results from an index and USE KEYS in a single query?

Union query is best option because USE KEYS can get directly from KV and other part of query can use index.

Related

Can a query only use one index per table?

I have a query like this:
( SELECT * FROM mytable WHERE author_id = ? AND seen IS NULL )
UNION
( SELECT * FROM mytable WHERE author_id = ? AND date_time > ? )
Also I have these two indexes:
(author_id, seen)
(author_id, date_time)
I read somewhere:
A query can generally only use one index per table when process the WHERE clause
As you see in my query, there is two separated WHERE clause. So I want to know, "only one index per table" means my query can use just one of those two indexes or it can use one of those indexes for each subquery and both indexes are useful?
In other word, is this sentence true?
"always one of those index will be used, and the other one is useless"
That statement about only using one index is no longer true about MySQL. For instance, it implements the index merge optimization which can take advantage of two indexes for some where clauses that have or. Here is a description in the documentation.
You should try this form of your query and see if it uses index mer:
SELECT *
FROM mytable
WHERE author_id = ? AND (seen IS NULL OR date_time > ? );
This should be more efficient than the union version, because it does not incur the overhead of removing duplicates.
Also, depending on the distribution of your data, the above query with an index on mytable(author_id, date_time, seen) might work as well or better than your version.
UNION combines results of subqueries. Each subquery will be executed independent of others and then results will be merged. So, in this case WHERE limits are applied to each subquery and not to all united result.
In answer to your question: yes, each subquery can use some index.
There are cases when the database engine can use more indexes for one select statement, however when filtering one set of rows really it not possible. If you want to use indexing on two columns then build one index on both columns instead of two indexes.
Every single subquery or part of composite query is itself a query can be evaluated as single query for performance and index access .. you can also force the use of different index for eahc query .. In your case you are using union and these are two separated query .. united in a resulting query
. you can have a brief guide how mysql ue index .. acccessing at this guide
http://dev.mysql.com/doc/refman/5.7/en/mysql-indexes.html

(SQL) Union combination with additional data

I use a database program called Agility by WiSys at my job. I had an unusual occurrence where part the data I needed was found in one column of a specific table and the rest was in another column in another table.
I used a UNION to combine these tables, but I have found that I cannot add any more data needed for the rest of my report. When I do, I receive a Error Message stating: All queries combined using a UNION, INTERSECT OR EXCEPT operator must have an equal number of expressions in their target lists.
Basically, the UNION works as needed, I have combined my data into one column, however, I cannot call any additional data needed in the query because the UNION prevents that data from being called.
Here is my query without the additional data I need:
SELECT table1_sql.UnionColumn1,
FROM table1_sql
UNION
SELECT table2_sql.UnionColumn2 AS CombinedColumn
FROM table2_sql
ORDER BY CombinedColumn
I need to have the UNION with these extra columns in my report as well:
SELECT table1_sql.UnionColumn1,
table1_sql.ExtraColumn1,
table1_sql.ExtraColumn2,
table1_sql.ExtraColumn3,
table1_sql.ExtraColumn4
FROM table1_sql
UNION
SELECT table2_sql.UnionColumn2 AS CombinedColumn
FROM table2_sql
ORDER BY CombinedColumn
An example of the data that I am trying to retrieve would be:
Example Data Where Order_No is the data that I want to join via UNION and everything else is data that is also needed but not allowed with a UNION.
The program Agility is not as robust as other programs, so I am somewhat limited in my ability to complete this reports using alternatives to UNION. Please advice.
The error message is telling you the complete story. When using a union BOTH queries MUST have the same number of columns. You can work with it by simply adding some hard coded NULLS.
SELECT table1_sql.UnionColumn1,
table1_sql.ExtraColumn1,
table1_sql.ExtraColumn2,
table1_sql.ExtraColumn3,
table1_sql.ExtraColumn4
FROM table1_sql
UNION
SELECT table2_sql.UnionColumn2 AS CombinedColumn
, NULL
, NULL
, NULL
, NULL
FROM table2_sql
ORDER BY CombinedColumn
Please note you will have to order by UnionColumn1 because the column names in the second query are not the name of the columns in the final result set. Only the names from the first query.

MySql Duplicated rows string comparation performance

I have a table with more then 2 million records,
I need to find duplication records in column with string type additionaly I have index for this field.
I have next query:
select m.* from member as m
where lower(m.username) in
(select lower(b.username) from member as b
where b.Username like 'a%'
group by b.username
having count(b.username) >= 2);
sub-query return only 4 records less then 0.2 seconds, but if I use them in where conditions section, this query working very long time and never return results....
I have tried to run next query, that theoretically the same logic:
select * from member as m where lower(Username) in (lower('a1'),
lower('a2'),lower('a3'),lower('a4'));
and it works fine and fast.
what is the issues ?
additionally I would like to run query with out where b.Username like 'a%' part?
In common case MySQL can not use index for IN subqueries
This is sad, but, actually, MySQL can not recognize "constant subqueries". What does it mean? It means that if you have a subquery that returns static list of values - and you use that in IN within another query, MySQL will not use index (by range).
Why it is so?
Actually, the most correct point is - because MySQL treats following queries:
.. WHERE `field` IN ('foo', 'bar', 'baz')
and
.. WHERE `field` IN (SELECT `col` FROM t)
-as different queries (I'm assuming that column col in table t in second query have same values, i.e. 'foo', 'bar', 'baz'). First query is equivalent for it's "expected" case, i.e. for range of values. But second query is equal for = ANY subquery - and so MySQL will not use index for that.
What to do
Actually, your case and cases similar to it - are cases when it's better to split your query into two parts. First part will be retrieve static list of values from your table. Second part will substitute result of your first part into IN clause and then you'll get index using.
Alternative - you can use JOIN syntax for table to itself. That may seems useful if you want to resolve an issue with one query (or if your list is too long)

mysql query two tables, UNION and where clause

I have two tables.
I query like this:
SELECT * FROM (
Select requester_name,receiver_name from poem_authors_follow_requests as one
UNION
Select requester_name,receiver_name from poem_authors_friend_requests as two
) as u
where (LOWER(requester_name)=LOWER('user1') or LOWER(receiver_name)=LOWER('user1'))
I am using UNION because i want to get distinct values for each user if a user exists in the first table and in the second.
For example:
table1
nameofuser
peter
table2
nameofuser
peter
if peter is on either table i should get the name one time because it exists on both tables.
Still i get one row from first table and a second from table number two. What is wrong?
Any help appreciated.
There are two problems with your SQL:
(THis is not the question, but should be considered) by using WHERE over the UNION instead of the tables, you create a performance nightmare: MySQL will create a temporary table containing the UNION, then query it over the WHERE. Using a calculation on a field (LOWER(requester_name)) makes this even worse.
The reason you get two rows is, that UNION DISTINCT will only suppress real duplicates, so the tuple (someuser,peter) and the tuple (someotheruser, peter) will result in duplication.
Edit
To make (someuser, peter) a duplicate of (peter, someuser) you could use:
SELECT
IF(requester_name='peter', receiver_name, requester_name) AS otheruser
FROM
...
UNION
SELECT
IF(requester_name='peter', receiver_name, requester_name) AS otheruser
FROM
...
So you only select someuser which you already know : peter
You need the where clause on both selects:
select requester_name, receiver_name
from poem_authors_follow_requests
where LOWER(requester_name) = LOWER('user1') or LOWER(receiver_name) = LOWER('user1')
union
select requester_name, receiver_name
from poem_authors_friend_requests
where LOWER(requester_name) = LOWER('user1') or LOWER(receiver_name) = LOWER('user1')
The two queries are independent of each other, so you shouldn't try to connect them other than by union.
You can use UNION if you want to select rows one after the other from several tables or several sets of rows from a single table all as a single result set.
UNION is available as of MySQL 4.0. This section illustrates how to use it.
Suppose you have two tables that list prospective and actual customers, a third that lists vendors from whom you purchase supplies, and you want to create a single mailing list by merging names and addresses from all three tables. UNION provides a way to do this. Assume the three tables have the following contents:
http://w3webtutorial.blogspot.com/2013/11/union-in-mysql.html
You are doing the union before and then applying the where clause. So you would get a unique combination of "requester_name,receiver_name" and then the where clause would apply. Apply the where clause in each select...
Select requester_name,receiver_name from poem_authors_follow_requests
where (LOWER(requester_name)=LOWER('user1')
or LOWER(receiver_name)=LOWER('user1'))
UNION
Select requester_name,receiver_name from poem_authors_friend_requests
where (LOWER(requester_name)=LOWER('user1')
or LOWER(receiver_name)=LOWER('user1'))
In your where statement, reference the alias "u" for each field refence in your where statement.
So the beginning of your where statement would be like: where (LOWER(u.requester_name) = ...
This is simlar to the answer you can see in: WHERE statement after a UNION in SQL?
You should be able to use the INTERSECT keyword instead of doing a nested query on a UNION.
SELECT member_id, name FROM a
INTERSECT
SELECT member_id, name FROM b
can simply be rewritten to
SELECT a.member_id, a.name
FROM a INNER JOIN b
USING (member_id, name)
http://www.bitbybit.dk/carsten/blog/?p=71

Search SQL query from multiple tables MySQL

I am trying to perform search on multiple tables.
I will simplify problem and say that I have 2 tables Worker and Customer both have Id, Name, Surname and Worker has additional Position, all fields are varchar except Id which is Int.
How to make a query that will return rows of either Customer or Worker, where one of theirs fields contains entered search string.
I have tried with joins but I got returned joined row also.
select id,name,surname,position,'worker' as tbl from worker where ..
union all
select id,name,surname,'','customer' from customer where ...
In this way you can even know results what table belong to.
Just UNION both queries.
If you really can JOIN those two, you can use
an IF statement in the SELECT clause to show the right field.
But, from what I understand from your question, go with UNION