I have a problem.... here is a part of sample query:
select * from tablename WHERE (id = "some4294-0643-4eaa-a262-7479c1859860" OR code = "some4294-0643-4eaa-a262-7479c1859860")
and deleted is null and blablablabla...>
And there are 2 indexes on this table: id and code.
If I'm querying tablename this way, indexes are not used.
In other query: select from (select * from tablename WHERE (id = "some4294-0643-4eaa-a262-7479c1859860" OR code = "some4294-0643-4eaa-a262-7479c1859860"))
where deleted is null and blablablabla...>
Indexes are used.
problem is my query is even more complex..... and I don't really want to deal with select in select.... but I really wish indexes to be used...
Is there any way to build index for 1st statement?
Related
I just can't figure it out why this query work
SELECT id, name, organization_id
FROM facilities
WHERE organization_id = ANY(
'{abc-xyz-123,678-ght-nmp}'
)
But this query wont work with error operator does not exist: uuid = uuid[]
SELECT id, name, organization_id
FROM facilities
WHERE organization_id = ANY(
SELECT organization_ids
FROM admins
WHERE id = 'jkl-iop-345'
)
When the subquery
SELECT organization_ids
FROM admins
WHERE id = 'jkl-iop-345'
give the exact result of {abc-xyz-123,678-ght-nmp}.
I'm using postgres (PostgreSQL) 13.3
The subquery produces one row that contains an array.
If you use = ANY (SELECT ...), the result set is converted to an array, so you end up with
{{abc-xyz-123,678-ght-nmp}}
which is an array of arrays.
You probably want
SELECT id, name, organization_id
FROM facilities
WHERE EXISTS (SELECT 1 FROM admins
WHERE admins.id = 'jkl-iop-345'
AND facilities.organization_id = ANY (admins.organization_ids)
);
Let me remark that storing references to other tables in an array, JSON or other composite data type is an exceptionally bad idea. A normalized schema with a junction table would serve you better.
I have one table which contains "133,072,194" records and I am trying to execute
SELECT COUNT(test)
FROM mytable
WHERE test = false
but it is taking Execution time: 128320.712 ms
I already have indexing on test column. Could you please let me know, what I can optimize or change, so my query became faster?
Because of this, my other select query is also not working.
If there are many rows where test is FALSE, you won't be able to get an exact result faster than with a sequential scan, which is slow for big tables.
If you have only few rows that satisfy the condition, you should create a partial index:
CREATE INDEX mytable_notest_ind ON mytable(id) WHERE NOT test;
(assuming that id is the primary key) and keep mytable autovacuumed often enough that you get an index only scan.
But usually exact results for queries like this are not required.
You could calculate an estimated count from the table statistics with a query like this:
SELECT t.reltuples
* (1 - t.nullfrac)
* mcv.freq AS count_false
FROM pg_stats AS s
CROSS JOIN LATERAL unnest(s.most_common_vals::text::boolean[],
s.most_common_freqs) AS mcv(val, freq)
JOIN pg_class AS t
ON s.tablename = t.relname
AND s.schemaname = t.relnamespace::regnamespace::text
WHERE s.tablename = 'mytable'
AND s.attname = 'test'
AND mcv.val = FALSE;
That would be very fast.
See my blog post for more considerations about the speed of SELECT count(*).
I have a query where I'm trying to find a null field from millions of records. There will only be one or two.
The query looks like this:
SELECT *
FROM “table”
WHERE “id” = $1
AND “end_time” IS NULL
ORDER BY “start_time” DESC LIMIT 1
How can I make this query more performant eg using indexes in the database.
try a partial index, smth like:
create index iname on "table" (id, start_time) where end_time is null;
I am unable to fetch primary key in DB2. I used following code but It is not working for me.
SELECT TBCREATOR, TBNAME, NAME, KEYSEQ
FROM SYSIBM.SYSCOLUMNS
WHERE TBCREATOR = 'DSN8710'
AND TBNAME = 'EMPLOYEE'
AND KEYSEQ > 0
ORDER BY KEYSEQ;
And what is the means of TBCREATOR in this code and how to modified TBCREATOR value according to my case?
I'll answer your last question first. creator is sometimes referred to as schema. If you're familiar with Oracle, this is roughly analogous to a database user (though not exactly).
As far as getting the "primary key" information, you probably want to know which index is the "clustering" index (which is what usually, but not always, determines the physical ordering of the rows on disk).
How you find the clustering index depends on the platform you're running:
Mainframe (z/OS):
SELECT
RTRIM(name) AS index_name
,RTRIM(creator) AS index_schema
,uniquerule
,clustering
FROM sysibm.sysindexes
WHERE tbname = #table
AND tbcreator = #schema
AND clustering = 'Y'
Then, to see the actual columns in that index, you perform this query:
SELECT colname AS name
FROM sysibm.sysindexes a
JOIN sysibm.syskeys b
ON a.name = b.ixname
AND a.tbcreator = b.ixcreator
WHERE a.name = #index_name
AND a.tbcreator = #index_schema
ORDER BY COLSEQ
Linux/Unix/Windows:
SELECT
RTRIM(indname) AS index_name
,RTRIM(indschema) AS index_schema
,uniquerule
,indextype
FROM syscat.indexes
WHERE tabname = #table
AND tabschema = #schema
AND indextype = 'CLUS'
Then, to see the actual columns in that index, you perform this query:
SELECT colnames as name
FROM sysibm.sysindexes
WHERE name = #index_name
AND tbcreator = #index_schema
ORDER BY NAME
LUW returns the list of columns as one string, delimited by +, which is kind of weird...
I'd like to count all the Orders that are not urgent and whose order status = 1 (shipped).
This should be a very simple query to optimize. I'd like to put a simple filtered index on the Orders table to cover this query to make it a constant time/O(1) operation. However, when I look at the query plan, it looks like it's using a Index Scan which doesn't make sense. Ideally, this query should just returning the number of items in the index.
The table look like this (simplified to get to the essence):
CREATE TABLE [dbo].[Orders](
[Id] [int] IDENTITY(1,1) NOT NULL,
[IsUrgent] [bit] NOT NULL,
[Status] [tinyint] NOT NULL
CONSTRAINT [PK_Orders] PRIMARY KEY CLUSTERED ( [Id] ASC )
I've created this filtered index:
CREATE INDEX IX_Orders_ShippedNonUrgent ON Orders(Id) WHERE IsUrgent = 0 AND Status = 1;
Now, when I do this query:
SELECT COUNT(*) FROM Orders WHERE IsUrgent = 0 AND Status = 1
I see that the query plan is using IX_Orders_ShippedNonUrgent, but it's doing an Index Scan and performing around 200 reads across the ~150,000 rows in Orders.
Is it possible to always have this query run in constant time assuming the filtered index is kept up to date? Ideally, it should only perform 1 read to get the size of the index.
If I switch to a non-filtered index like this:
CREATE INDEX IX_Orders_IsUrgentStatus ON Orders(IsUrgent, Status);
The query plan uses an Index Seek, but still performs many more reads than should be necessary to answer this simple query.
UPDATE
I'm able to do this
SELECT TOP 1 rows FROM sys.partitions p
INNER JOIN sys.indexes i
ON i.name = 'IX_Orders_ShippedNonUrgent'
AND i.object_id = p.object_id
AND i.index_id = p.index_id
and get the result in 9 reads but it seems like there should be a much easier and less brittle way of using the simple COUNT(*) query.
It seems like what I'm wanting isn't possible. The best answer was left in the comments by Nikola Markovinović which is to forget about the filtered index and use an indexed view instead:
CREATE VIEW [dbo].vw_Orders_TotalShippedNonUrgent WITH SCHEMABINDING
AS
SELECT COUNT_BIG(*) AS TotalOrders
FROM dbo.Orders WHERE IsUrgent = 0 AND Status = 1;
with
CREATE UNIQUE CLUSTERED INDEX IX_vw_Orders_TotalShippedNonUrgent ON vw_Orders_TotalShippedNonUrgent(TotalOrders);
This forces creating views and their index for each summary statistic that I want as well as rewriting the query to ask the view instead of the simple approach, but it is fast at only 2 reads.
I'll leave this question open for awhile in case anyone has a simpler approach that's just as fast.