SQL Select query optimization with indexing - sql

A posts table contains 1 million rows. This table has a field with the name poster_id.
I have a list of followers by this poster_id.
I am trying to get a list of all activities from this followers (35 in this case but less or more is possible) in the last 48 hours.
I use this query:
SELECT post_id
, topic_id
, poster_id
, post_time
FROM posts
WHERE post_time > 1606833542
AND poster_id IN (80202, 74247, 79290, 72488,
111751, 85040, 100256, 68025,
101088, 101598, 101950, 103252,
103071, 80063, 100372, 102530, 109961,
109854, 105626, 108967, 110391, 104423,
113243, 111673, 113979, 104670, 127318,
68252, 109606, 121393, 122991, 124489,
127723, 126525)
ORDER
by post_time
LIMIT 100
Problem:
This query takes too long (0.4000 seconds) to execute.
The poster_id has an index of the post table.
How can I make this query faster?

try avoid the IN clause and use a join
SELECT
p.post_id
, p.topic_id
, p.poster_id
, p.post_time
FROM posts p
INNER JOIN (
SELECT 80202 poster_id
UNION SELECT 74247
UNION SELECT 79290
UNION SELECT 72488
UNION SELECT 111751
UNION SELECT 85040
UNION SELECT 100256
UNION SELECT 68025
UNION SELECT 101088
UNION SELECT 101598
UNION SELECT 101950
UNION SELECT 103252
UNION SELECT 103071
UNION SELECT 80063
UNION SELECT 100372
UNION SELECT 102530
UNION SELECT 109961
UNION SELECT 109854
UNION SELECT 105626
UNION SELECT 108967
UNION SELECT 110391
UNION SELECT 104423
UNION SELECT 113243
UNION SELECT 111673
UNION SELECT 113979
UNION SELECT 104670
UNION SELECT 127318
UNION SELECT 68252
UNION SELECT 109606
UNION SELECT 121393
UNION SELECT 122991
UNION SELECT 124489
UNION SELECT 127723
UNION SELECT 126525
) t ON t.poster_id = p.poster_id
AND p.post_time > 1606833542
ORDER by p.post_time LIMIT 100
could be the value in the IN clause are form some subquery in this case ypou could use the related subquery instead of the UNION .....
WHERE IN clase is the same as serverl OR condition (several internal subquery) .. instead INNER JOIN just check the values in a single operation
for better performance, instead of you actual index on poster_id, you could try using a redundant index adding all the columns you select in your index eg:
create index my_index on posts (poster_id, post_id, topic_id , post_time )
in this way all the query value are obtained using the index and the query don't need to access at the table ..

Related

Union All have mismatched column count

I am trying to union some table. But I am having some issues with the query as I have the following error:
Queries in UNION ALL have mismatched column count; query 1 has 10 columns, query 2 has 12 columns at [3:1]
The query used is:
SELECT * FROM `table_1`
UNION ALL
SELECT * ,null, FROM `table_2`
UNION ALL
SELECT * FROM `table_3`
UNION ALL
SELECT * FROM `table_4`
UNION ALL
SELECT * , null, FROM `table_5`
Please someone have any suggestions?
In a UNION ALL all queries need to be the same number of columns.
You need to post the schema of all tables. But according to the error message you posted, this could help for the 2 first tables:
SELECT *, null FROM `table_1` -- assuming table_1 has 10 columns, add 1 more empty to match the table_2
UNION ALL
SELECT * FROM `table_2` -- assuming table_2 has 11 columns
-- make the same to the rest of queries
-- UNION ALL
-- SELECT * FROM `table_3`
-- UNION ALL
-- SELECT * FROM `table_4`
-- UNION ALL
-- SELECT * , null, FROM `table_5`
Update:
Adding a example of union all declaring the columns:
SELECT
col1_str,
col2_str,
col3_int,
col4_int
FROM `table_1`
UNION ALL
SELECT
col2_str,
FORMAT_DATE("%Y-%m-%d", col1_date) as col1_str, -- transform a date column to string
col3_int,
null
FROM `table_2`

replacement of Offset Limit in SQL Server

We have DataTemp table which has the records in desc order.
select * from (
select 9,'a',3 union
select 8,'a',2 union
select 7,'b',3 union
select 6,'a',1 union
select 5,'b',2 union
select 4,'c',3 union
select 3,'c',2 union
select 2,'b',1 union
select 1,'c',1
) door (sno,id, N_th_Reocord)
sno - Auto Id.
id - code of the Doors*.
N_th_Record - for denoting the n the record.
At a time, only three* records per Door are need to store on this table. For example Door 'a' has new entry(means 4th record) then first of 'a' Door need to delete.
4th record:
select * from (
select 10,'a',4 union --- new entry
select 9,'a',3 union
select 8,'a',2 union
select 7,'b',3 union
select 6,'a',1 union -- need to delete
select 5,'b',2 union
select 4,'c',3 union
select 3,'c',2 union
select 2,'b',1 union
select 1,'c',1
) door (sno,id, N_th_Reocord)
I do following query. But I need easiest way for deleting the row. Because, we are try to reduce the time consumption of over all project.
delete from door where sno = (
select sno from (
select 10,'a',4 union
select 9,'a',3 union
select 8,'a',2 union
select 7,'b',3 union
select 6,'a',1 union
select 5,'b',2 union
select 4,'c',3 union
select 3,'c',2 union
select 2,'b',1 union
select 1,'c',1
) door (sno,id, N_th_Reocord)
where id = 'a'
order by sno desc -- For 'DataTemp' *order by* is no needed.
offset 3 rows fetch next 1 rows only
)
Note:
Three rows and three Door are given for example. Actually we work with 144 rows per 12 Doors.
Before this delete, we check lot of Business rules.
Version: SQL Server 2012
You could use ROW_NUMBER:
WITH cte AS (SELECT *,ROW_NUMBER() OVER(PARTITION BY id ORDER BY sno DESC) rn FROM t)
DELETE FROM cte WHERE rn > 3;
db<>fiddle demo

sql server join with regex performance

i have to match 2 tables with a column that have values with similar values.
ex:
select * from(
select 'value**'c1 union all
select 'value11'c1 union all
select 'value**\value22'c1 union all
select 'value34\value**'c1 union all
select 'asd\value**\sdf**'c1)t1
right join
(
select 'value11'c1 union all
select 'value24'c1 union all
select 'value54'c1 union all
select 'value54\value22'c1 union all
select 'value11\value43'c1 union all
select 'asd\value21\sdf22'c1 union all
select 'asd\value21\sdf23'c1 union all
select 'asd\value21\sdf24'c1 union all
select 'rew\value21\sdf24'c1 union all
select 'asd\value21'c1)t2
on t2.c1 like replace(t1.c1,'*','[a-Z0-9]')
that s working fine, but performance with lots of records(>300000) needs almost a hour.
someone have ideas to have a better query?
thank you in advance!
i tried to add the condition on join
and LEN(t2.c1)=LEN(t1.c1)
but same slow result...

Oracle SQL Query IN

I have following query, that's not working.
select * from table where id in (
1,2, (select id from another_table)
)
How i can rewrite it?
How about
select * from table
where id in (1,2)
or id in (select id from another_table)
Take care and use parentheses when adding additional WHERE-conditions using and!!!
select *
from table
where id in (1,2) OR id in(
select id from another_table
)
select * from table where id in (
select 1 as id from dual
union all
select 2 as id from dual
union all
select id from another_table
)
select * from table where id in (
select 1 from dual
union all
select 2 from dual
union all
select id from another_table);
I'm using union because this is faster than using an OR clause which also can be used.

SQL Select Condition Question

I have a quick question about a select statement condition.
I have the following table with the following items. What I need to get is the object id that matches both type id's.
TypeId ObjectId
1 10
2 10
1 11
So I need to get both object 10 because it matches type id 1 and 2.
SELECT ObjectId
FROM Table
WHERE TypeId = 1
AND TypeId = 2
Obviously this doesn't work because it won't match both conditions for the same row. How do I perform this query?
Also note that I may pass in 2 or more type id's to narrow down the results.
Self-join:
SELECT t1.ObjectId
FROM Table AS t1
INNER JOIN Table AS t2
ON t1.ObjectId = t2.ObjectId
AND t1.TypeId = 1
AND t2.TypeId = 2
Note sure how you want the behavior to work when passing in values, but that's a start.
I upvoted the answer from #Cade Roux, and that's how I would do it.
But FWIW, here's an alternative solution:
SELECT ObjectId
FROM Table
WHERE TypeId IN (1, 2)
GROUP BY ObjectId
HAVING COUNT(*) = 2;
Assuming uniqueness over TypeId, ObjectId.
Re the comment from #Josh that he may need to search for three or more TypeId values:
The solution using JOIN requires a join per value you're searching for. The solution above using GROUP BY may be easier if you find yourself searching for an increasing number of values.
This code is written with Oracle in mind. It should be general enough for other flavors of SQL
select t1.ObjectId from Table t1
join Table t2 on t2.TypeId = 2 and t1.ObjectId = t2.ObjectId
where t1.TypeId = 1;
To add additional TypeIds, you just have to add another join:
select t1.ObjectId from Table t1
join Table t2 on t2.TypeId = 2 and t1.ObjectId = t2.ObjectId
join Table t3 on t3.TypeId = 3 and t1.ObjectId = t3.ObjectId
join Table t4 on t4.TypeId = 4 and t1.ObjectId = t4.ObjectId
where t1.TypeId = 1;
Important note: as you add more joins, performance will suffer a LOT.
In regards to Bill's answer you can change it to the following to get rid of the need to assume uniqueness:
SELECT ObjectId
FROM (SELECT distinct ObjectId, TypeId from Table)
WHERE TypeId IN (1, 2)
GROUP BY ObjectId
HAVING COUNT(*) = 2;
His way of doing it scales better as the number of types gets larger.
Try this
Sample Input:(Case 1)
declare #t table(Typeid int,ObjectId int)
insert into #t
select 1,10 union all select 2,10 union all
select 1,11
select * from #t
Sample Input:(Case 2)
declare #t table(Typeid int,ObjectId int)
insert into #t
select 1,10 union all select 2,10 union all
select 3,10 union all select 4,10 union all
select 5,10 union all select 6,10 union all
select 1,11 union all select 2,11 union all
select 3,11 union all select 4,11 union all
select 5,11 union all select 1,12 union all
select 2,12 union all select 3,12 union all
select 4,12 union all select 5,12 union all
select 6,12
select * from #t
Sample Input:(Case 3)[Duplicate entries are there]
declare #t table(Typeid int,ObjectId int)
insert into #t
select 1,10 union all select 2,10 union all
select 1,10 union all select 2,10 union all
select 3,10 union all select 4,10 union all
select 5,10 union all select 6,10 union all
select 1,11 union all select 2,11 union all
select 3,11 union all select 4,11 union all
select 5,11 union all select 1,12 union all
select 2,12 union all select 3,12 union all
select 4,12 union all select 5,12 union all
select 6,12 union all select 3,12
For case 1, the output should be 10
For case 2 & 3, the output should be 10 and 12
Query:
select X.ObjectId from
(
select
T.ObjectId
,count(ObjectId) cnt
from(select distinct ObjectId,Typeid from #t)T
where T.Typeid in(select Typeid from #t)
group by T.ObjectId )X
join (select max(Typeid) maxcnt from #t)Y
on X.cnt = Y.maxcnt