Lucene Grails Searchable plugin build index for part of the table - grails

I have a searchable domain class mapped to a table that has a flag column. Currently, when Lucene creates an index it generates a query like this (returns all data in the table):
select this_.id as id0_0_,
this_.flag as flag2_0_0_,
this_.email as email0_0_, this_.first_name as first6_0_0_, this_.last_name as last8_0_0_
from ais_person this_
order by this_.id asc
Is it possible to build an index for only those rows which contain a specific flag value, so that the generated query would look like this:
select this_.id as id0_0_,
this_.flag as flag2_0_0_,
this_.email as email0_0_, this_.first_name as first6_0_0_, this_.last_name as last8_0_0_
from ais_person this_
where this_.flag = 'Y'
order by this_.id asc

Yes, i think you can do that. Following is the pseudo-code.
Document doc = new Document();
doc.add(Field.Text("flag", Y));

Related

Optimizing SQL query using JOIN instead of NOT IN

I have a sql query that I'd like to optimize. I'm not the designer of the database, so I have no way of altering structure, indexes or stored procedures.
I have a table that consists of invoices (called faktura) and each invoice has a unique invoice id. If we have to cancel the invoice a secondary invoice is created in the same table but with a field ("modpartfakturaid") referring to the original invoice id.
Example of faktura table:
invoice 1: Id=152549, modpartfakturaid=null
invoice 2: Id=152592, modpartfakturaid=152549
We also have a table called "BHLFORLINIE" which consists of services rendered to the customer. Some of the services have already been invoiced and match a record in the invoice (FAKTURA) table.
What I'd like to do is get a list of all services that either does not have an invoice yet or does not have an invoice that's been cancelled.
What I'm doing now is this:
`SELECT
dbo.BHLFORLINIE.LeveringsDato AS treatmentDate,
dbo.PatientView.Navn AS patientName,
dbo.PatientView.CPRNR AS patientCPR
FROM
dbo.BHLFORLINIE
INNER JOIN dbo.BHLFORLOEB
ON dbo.BHLFORLOEB.BhlForloebID = dbo.BHLFORLINIE.BhlForloebID
INNER JOIN dbo.PatientView
ON dbo.PatientView.PersonID = dbo.BHLFORLOEB.PersonID
INNER JOIN dbo.HENVISNING
ON dbo.HENVISNING.BhlForloebID = dbo.BHLFORLOEB.BhlForloebID
LEFT JOIN dbo.FAKTURA
ON dbo.BHLFORLINIE.FakturaId = FAKTURA.FakturaId
WHERE
(dbo.BHLFORLINIE.LeveringsDato >= '2017-01-01' OR dbo.BHLFORLINIE.FakturaId IS NULL) AND
dbo.BHLFORLINIE.ProduktNr IN (110,111,112,113,8050,4001,4002,4003,4004,4005,4006,4007,4008,4009,6001,6002,6003,6004,6005,6006,6007,6008,7001,7002,7003,7004,7005,7006,7007,7008) AND
((dbo.FAKTURA.FakturaType = 0 AND
dbo.FAKTURA.FakturaID NOT IN (
SELECT FAKTURA.ModpartFakturaID FROM FAKTURA WHERE FAKTURA.ModpartFakturaID IS NOT NULL
)) OR
dbo.FAKTURA.FakturaType IS NULL)
GROUP BY
dbo.PatientView.CPRNR,
dbo.PatientView.Navn,
dbo.BHLFORLINIE.LeveringsDato`
Is there a smarter way of doing this? Right now the added the query performs three times slower because of the "not in" subquery.
Any help is much appreciated!
Peter
You can use an outer join and check for null values to find non matches
SELECT customer.name, invoice.id
FROM invoices i
INNER JOIN customer ON i.customerId = customer.customerId
LEFT OUTER JOIN invoices i2 ON i.invoiceId = i2.cancelInvoiceId
WHERE i2.invoiceId IS NULL

Solving a PG::GroupingError: ERROR

The following code gets all the residences which have all the amenities which are listed in id_list. It works with out a problem with SQLite but raises an error with PostgreSQL:
id_list = [48, 49]
Residence.joins(:listed_amenities).
where(listed_amenities: {amenity_id: id_list}).
references(:listed_amenities).
group(:residence_id).
having("count(*) = ?", id_list.size)
The error on the PostgreSQL version:
What do I have to change to make it work with PostgreSQL?
A few things:
references should only be used with includes; it tells ActiveRecord to perform a join, so it's redundant when using an explicit joins.
You need to fully qualify the argument to group, i.e. group('residences.id').
For example,
id_list = [48, 49]
Residence.joins(:listed_amenities).
where(listed_amenities: { amenity_id: id_list }).
group('residences.id').
having('COUNT(*) = ?", id_list.size)
The query the Ruby (?) code is expanded to is selecting all fields from the residences table:
SELECT "residences".*
FROM "residences"
INNER JOIN "listed_amenities"
ON "listed_amentities"."residence_id" = "residences"."id"
WHERE "listed_amenities"."amenity_id" IN (48,49)
GROUP BY "residence_id"
HAVING count(*) = 2
ORDER BY "residences"."id" ASC
LIMIT 1;
From the Postgres manual, When GROUP BY is present, it is not valid for the SELECT list expressions to refer to ungrouped columns except within aggregate functions or if the ungrouped column is functionally dependent on the grouped columns, since there would otherwise be more than one possible value to return for an ungrouped column.
You'll need to either group by all fields that aggregate functions aren't applied to, or do this differently. From the query, it looks like you only need to scan the amentities table to get the residence ID you're looking for:
SELECT "residence_id"
FROM "listed_amenities"
WHERE "listed_amenities"."amenity_id" IN (48,49)
GROUP BY "residence_id"
HAVING count(*) = 2
ORDER BY "residences"."id" ASC
LIMIT 1
And then fetch your residence data with that ID. Or, in one query:
SELECT "residences".*
FROM "residences"
WHERE "id" IN (SELECT "residence_id"
FROM "listed_amenities"
WHERE "listed_amenities"."amenity_id" IN (48,49)
GROUP BY "residence_id"
HAVING count(*) = 2
ORDER BY "residences"."id" ASC
LIMIT 1
);

Optimize Grails Queries

I'm trying to optimize the speed in my grails app.
I have this:
Catalog a= Catalog.findByName('a');
Element b= Element.findByCatalogAndNumber(a,2);
This way i can find b.
But I'm thinking I could use something like this:
Element b= Element.createCriteria().get{
catalog{
eq("name",'a')
}
eq("number",2)
}
But I'm not sure if it reduces the queries to the database, or I'm just making a fool of myself and creating even bigger files and reducing the speed of my app by doing this.
any idea?
I have compared three versions of your query using
Grails 2.4.4, default settings for caches in a the Grails application
PostgreSQL 8.4, SQL statement logging has been turned on to count/see the SQL queries.
The first versions one using two calls on the Grails domain class:
def query1() {
Catalog a = Catalog.findByName('a');
log.info(a)
Element b = Element.findByCatalogAndPos(a, 2);
log.info(b)
render(b.toString())
}
The 2nd one using criteria
def query2() {
Element b = Element.createCriteria().get {
catalog {
eq("name", "a")
}
eq("pos", 2)
}
render(b.toString())
}
and the last one using a where query
def query3() {
def query = Element.where {
catalog.name == "a" && pos == 2
}
Element b = query.get()
render(b.toString())
}
The first one results in two SQL queries, the other ones will only send one query to the database (using an inner join from Element to Catalog).
As for readability/expressiveness, choose the 3rd version: It expresses your intention in a single line, and it's the most compact version.
As for performance, choose the 2nd or the 3rd version. Under high load, many concurrent users/requests, the number of queries does matter. This might not be an issue for all applications.
Anway, I'd always choose the 3rd version for the expressiveness; and it will scale, if the query conditions gets more complex over the time.
Update
The SQL statements used by the 1st version:
select this_.id as id1_1_0_, this_.version as version2_1_0_, this_.date_created as date_cre3_1_0_, this_.last_updated as last_upd4_1_0_, this_.name as name5_1_0_, this_.remark as remark6_1_0_
from catalog this_
where this_.name=$1 limit $2
Parameter: $1 = 'a', $2 = '1'
select this_.id as id1_2_0_, this_.version as version2_2_0_, this_.catalog_id as catalog_3_2_0_, this_.date_created as date_cre4_2_0_, this_.last_updated as last_upd5_2_0_, this_.pos as pos6_2_0_, this_.remark as remark7_2_0_
from element this_
where this_.catalog_id=$1 and this_.pos=$2 limit $3
Parameter: $1 = '10', $2 = '2', $3 = '1'
The SQL statement for the 2nd and 3rd version:
select this_.id as id1_2_1_, this_.version as version2_2_1_, this_.catalog_id as catalog_3_2_1_, this_.date_created as date_cre4_2_1_, this_.last_updated as last_upd5_2_1_, this_.pos as pos6_2_1_, this_.remark as remark7_2_1_, catalog_al1_.id as id1_1_0_, catalog_al1_.version as version2_1_0_, catalog_al1_.date_created as date_cre3_1_0_, catalog_al1_.last_updated as last_upd4_1_0_, catalog_al1_.name as name5_1_0_, catalog_al1_.remark as remark6_1_0_
from element this_ inner join catalog catalog_al1_
on this_.catalog_id=catalog_al1_.id
where (catalog_al1_.name=$1) and this_.pos=$2
Parameter: $1 = 'a', $2 = '2'

Changing my query into a stored procedure?

Here is the query (MS SQL):
use DB_432799_satv
select [DB_432799_satv].[dbo].ac_Orders.OrderNumber, OrderDate, PaymentDate,
CompletedDate, ShipDate,DateTimeFinishedPicking,DateTimeShipped,
ShipMethodName, PaymentMethodName
from [DB_432799_satv].[dbo].ac_Orders
Inner join [DB_432799_satv].[dbo].ac_Payments on
[DB_432799_satv].[dbo].ac_Orders.OrderId =
[DB_432799_satv].[dbo].ac_Payments.OrderId
Inner join [DB_432799_satv].[dbo].ac_OrderShipments on
[DB_432799_satv].[dbo].ac_Orders.OrderId =
[DB_432799_satv].[dbo].ac_OrderShipments.OrderId
Inner join [DB_432799_satv].[dbo].[ac_Transactions] on
[DB_432799_satv].[dbo].ac_Payments.paymentid =
[DB_432799_satv].[dbo].ac_Transactions.paymentid
Inner join [SuperATV].[dbo].[tblPartsBoxHeader] on
[DB_432799_satv].[dbo].[ac_transactions].[ProviderTransactionId] =
[SuperATV].[dbo].[tblPartsBoxHeader].[ordernumber]
How would I change this into a stored procedure?
I suspect what you want is what a "view" will give you. Specifically, to store that query in the database and select from it like:
SELECT * FOM myLongQueryView WHERE OrderNumber = 1234;
I don't develop MSSQL, but a quick search turned up this doc page on msdn. I suppose it would go something like this:
CREATE VIEW [DB_432799_satv].myLongQueryView
AS
select [DB_432799_satv].[dbo].ac_Orders.OrderNumber, OrderDate, PaymentDate,
CompletedDate, ShipDate,DateTimeFinishedPicking,DateTimeShipped,
ShipMethodName, PaymentMethodName
from [DB_432799_satv].[dbo].ac_Orders
...
Simply prepend your query with CREATE VIEW [DB_432799_satv].myLongQueryView AS, and use the docs page to decide if any options are desired.
It's important to note that query is stored, not it's current results. So it stays up to date with your data. It is joinable, aggregatable, etc...

How do list most linked issues using either Jira advanced query or JQL

I am trying to figure out a query where top 10 linked issues are returned. I know there is linkedIssues(issueKey,linkType) but it works on single issuekey for each call.
Is there a call similar like below, (soory that sql is not error proofed)
select issue.id from issue where linkedIssues(issue.id) order by linkedIssues(issue.id) desc?
Yes, you can do this with SQL. The table issuelink is a relationship table with 'source', 'destination', and 'linktype' columns. The SQL query below would return all issues which have a destination link reference.
SELECT I.id, I.pkey, count(*) AS LinkCount
FROM jiraissue I
JOIN issuelink L on L.DESTINATION = I.ID
JOIN issuelinktype LT on LT.ID = L.LINKTYPE
WHERE LT.LINKNAME in ('Blocks', 'Cloners', 'Duplicate', 'Relates')
GROUP BY I.id, I.pkey
ORDER BY LinkCount DESC

Resources