I am using OrientDb 2.1-rc4 as a document database. I have a MyClass class that gets updated very frequently by a multithreded application. To improve performance I removed the link from the State class to MyClass, and added a link and index from MyClass to State. In order to get all instances of MyClass I need to get a list of State rids and then query the index. This query gets my State rids.
SELECT DISTINCT(roles.views.states.#rid)
FROM #12:1
returns
[["#14:0","#14:1"]]
This query finds the correct rids in the index.
SELECT FROM index:MyClass.state
where key in [#14:0,#14:1]
When I put the two queries together.
SELECT FROM index:MWorkUnit.state
where key in (SELECT DISTINCT(roles.views.states.#rid) FROM #12:1)
I get the following error.
java.lang.ClassCastException: com.orientechnologies.orient.core.sql.query.OSQLSynchQuery cannot be cast to java.util.List
How do I get OrientDB to treat my subquery as an rid list?
Edit:
This query works when not using the index.
SELECT FROM MWorkUnit
where state IN (SELECT expand(roles.views.states).#rid FROM #12:1)
This seems a bug on query against indexes: sub queries are not correctly evaluated. Please could you open a new issue or that?
This workaround should work:
SELECT FROM index:MWorkUnit.state
LET $list = (SELECT DISTINCT(roles.views.states.#rid) FROM #12:1)
where key in $list
Related
Table name: Employee
I have an array column name: ["a","b","c"]
and a value name -> "a" which i want to check if it is present in array.
Through sql query i am able to do using ANY clause:
SELECT *
FROM EMPLOYEE WHERE 'a' = ANY(name)
But when i try to do same through criteria query I run into issues as ANY() uses subquery as param.
Can someone help how to achieve same using criteria api without using subquery?
I have tried isMember,Any() In() using criteria query but none of that works.
I have problems with understanding of way couchbase query plan works.
I use SpringData with Couchbase 4.1 and I provide custom implementation of Couchbase Repository. Inside my custom implememtnation of Couchbase Repository I have below method:
String queryAsString = "SELECT MyDatabase.*, META().id as _ID, META().cas as _CAS FROM MyDatabase WHERE segmentId = $id AND _class = $class ORDER BY executionTime DESC LIMIT 1";
JsonObject params = JsonObject.create()
.put(CLASS_VARIABLE, MyClass.class.getCanonicalName())
.put(ID_VARIABLE, segmentId);
N1qlQuery query = N1qlQuery.parameterized(queryAsString, params);
List<MyClass> resultList = couchbaseTemplate.findByN1QL(query, SegmentMembers.class);
return resultList.isEmpty() ? null : resultList.get(0);
In a result, Spring Data produces following json object represented query to Couchbase:
{
"$class":"path/MyClass",
"statement":"SELECT MyDatabase.*, META().id as _ID, META().cas as _CAS from MyDatabase where segmentId = $id AND _class = $class ORDER BY executionTime DESC LIMIT 1",
"id":"6592c16a-c8ae-4a74-bc17-7e18bf73b3f8"
}
And the problem is with performance when I execute it via Java and N1QL Rest Api or via cbq consol. For execute this query in cbq I simply replace parameters reference with exact values.
After adding EXPLAIN clause before select statement I mentioned different execution plans. Execution this query as parameterized query via Java Spring Data or N1QL Rest Api I've mentioned that query doesn't use index that I created exactly for this case. Index definiton can be found below:
CREATE INDEX `testMembers` ON MyDatabase `m`(`_class`,`segmentId`,`executionTime`) WHERE (`_class` = "path/MyClass") USING GSI;
So, when I execute query via cbq consol, Couchbase uses my idnex and query performance is very good. But, when I execute this query via N1QL rest api or Java i see that query doesn't use my index. Below you can find part of execution plan that proves this fact:
"~children": [
{
"#operator": "PrimaryScan",
"index": "#primary",
"keyspace": "CSM",
"namespace": "default",
"using": "gsi"
},
So, the question is that the right and legal behavior of couchbase query optimizer? And does it mean that query plan does not take into account real values of parameters? And have I manually put values into query string or exist eny other way to use N1Ql parameterized query with correct index selection?
EDIT
According to shashi raj answer I add N1qlParams.build().adhoc(false) parameter to parameterized N1QL query. This doesn't solve my problem, because I still have performance problem with this query. Moreover, when I print query I see that it is the same as I described earlier. So, my query still wrong analyzed and cause performance decline.
first of all you need to know how N1QL parameterized queries works query should be passed as:
String query= select * from bucketName where _class=$_class and segmentId=$segmentId LIMIT $limit ;
Now the query should be passed as:
N1QL.parameterized(query,jsonObject,N1qlParams.build().adhoc(false));
where jsonObject will have all the placeholder values.
JsonObject jsonObject=JsonObject.create().put("_class","com.entity,user").put("segmentId","12345").put("limit",100);
N1qlParams.build().adhoc(false) is optional since if you want your query to be optimized it will make use of it. It makes use of LRU where it keeps track of previously query entered and it keeps record of it so that next time it doesn't need to parse query and fetch it from previous what we call as prepared statement.
The only problem is couchbase only keeps record of last 5000 queried.
The problem in your case is caused by the fact that you have an index with 'where' clause WHERE ( _class = "path/MyClass"), and at the same time, you passing the _class as a parameter in your query.
Thus, the query optimizer analyzing the parametrized query has no idea that this query might use an index created for _class = "path/MyClass", cause it's _class = $class in a select's where. Pretty simple, right?
So, don't pass any fields mentioned in your index's 'where' as select parameters. Instead, hardcode _class = "path/MyClass" in your select in the same way you did for create index. And everything should be fine.
Here's the ticket in the couchbase issue tracking system about that.
https://issues.couchbase.com/browse/MB-22185?jql=text%20~%20%22parameters%20does%20not%20use%20index%22
I am using jpa native query , but its not returning values from salias it returns values from S
Query query = em.createNativeQuery("Select S.\"MESSAGE\",S.\"DESTINATION\",S.\"SENT_DATE\",S.\"CLIENT_TRACKING_ID\",S.\"MESSAGE_COST\",S.\"sTId\",salias.\"STATUS\",salias.timeDate from \"sent_sms_view\" S left join ( Select Distinct on (\"SMS_ID\") R.\"SMS_ID\",R.\"STATUS\",R.timeDate from \"sms_receipt_view\" R Order By R.\"SMS_ID\",R.timeDate Desc)As salias on S.\"SYSTEM_TRACKING_ID\"=salias.\"SMS_ID\" where S.Id_systemUser=:systemUser and S.\"CLIENT_TRACKING_ID\"=:cTId");
query.setParameter("cTId", cTId);
query.setParameter("systemUser", systemUser);
if (query.getResultList().size() > 0){
List<Object> resultat = query.getResultList();
This is the Postgres query and it works fine
Select S."MESSAGE",S."DESTINATION",S."SENT_DATE",S."CLIENT_TRACKING_ID",S."MESSAGE_COST",S."sTId" ,salias."STATUS",salias.timeDate
from "sent_sms_view" S
left join ( Select Distinct on ("SMS_ID") R."SMS_ID",R."STATUS",R.timeDate from "sms_receipt_view" R Order By R."SMS_ID",R.timeDate Desc)As salias
on S."SYSTEM_TRACKING_ID"=salias."SMS_ID"
where S.Id_systemUser='101' and S."CLIENT_TRACKING_ID" ='abda';
Can anyone tell me what i am doing wrong.
I'm only guessing what you might be trying to do, since you haven't told us, but here's how I'm guessing it should probably look like:
SELECT S."MESSAGE", S."DESTINATION", S."SENT_DATE", S."CLIENT_TRACKING_ID", S."MESSAGE_COST", S."sTId", salias."STATUS", salias.timeDate
FROM "sent_sms_view" S
INNER JOIN "sms_receipt_view" AS salias on (S."SYSTEM_TRACKING_ID" = salias."SMS_ID")
WHERE S.Id_systemUser=:systemUser AND S."CLIENT_TRACKING_ID"=:cTId
However I don't see why you would have numerical IDs, such as Id_systemUser stored as strings. In fact that variable name indicates horrible database design. CamelCasing combined with underscores is something you must categorically avoid.
And you must never call query.getResultList() twice if you're looking for the same results. Simply store the List to a local variable and then use it.
While running the below query to get the latest message with the latest data using the createdOn column
i get the below error
select count(m) from MessageWorkFlowStatus mwfs1 where mwfs1.createdOn =(select max(createdOn) from MessageWorkFlowStatus mwfs2 where mwfs1.status= 'NEW' or mwfs1.status='IN PROGRESS')
The encapsulated expression is not a valid expression
Please let me know if i can run Query this way
First of all, count(m) is not correct. It should either be count(*) or count(mwfs1). Secondly, in your inner query, you are using status column from the outer query table (mswfs1) which is logically wrong. It should instead be mwfs2.status = 'NEW' or mwfs2.status = 'IN PROGRESS'.
I think your query should be:
select count(mwfs1)
from MessageWorkFlowStatus mwfs1
where mwfs1.createdOn = (
select max(createdOn)
from MessageWorkFlowStatus mwfs2
where mwfs2.status= 'NEW' or mwfs2.status='IN PROGRESS')
I recently encountered the following problem with buiding queries in jooq (version 3.1.0):
I want to build delete statement with order and limit constraints. So, my aim is to build something like this:
DELETE FROM table ORDER BY field DESC LIMIT 1 (this is MySql syntax)
But i haven't found nesessary methods in result delete query object:
DSLContext context = createContext();
DeleteWhereStep delete = context.delete(createTable(table));
DeleteConditionStep whereStep = delete.where(condition);
whereStep.orderBy(...)//and no such method here
There are all nesessary methods in select statements and none for delete.
Is it possible to set order and limit for delete request in jooq?
As of jOOQ 3.2, these sorts of extensions are currently not implemented yet. Chances are, that #203 could be implemented in jOOQ 3.3, though.
In the mean time, you have two options:
Resort to plain SQL
i.e. write something like:
context.execute("DELETE FROM {0} ORDER BY {1} DESC LIMIT 1",
createTable(table),
field);
Manually transform your SQL statement into something equivalent
I suspect that the ORDER BY .. LIMIT extension to the MySQL DELETE statement is just sugar for:
DELETE FROM table t
WHERE t.id IN (
SELECT id FROM table
ORDER BY field LIMIT 1
)
Or with jOOQ:
context.delete(TABLE)
.where(TABLE.ID.in(
select(TABLE.ID)
.from(TABLE)
.orderBy(TABLE.FIELD)
.limit(1)
))