If i use a table containing at least 2 columns like this :
[User]
[FirstName]|[LastName]
Robert-Dupont
Louis-Dupont
Georges-Andre
Assuming that there is a huge amount of data and that there is much more unique result in 'FirstName' than in 'LastName', which query is the fastest :
Query 1 :
SELECT * USER WHERE LastName = 'Dupont' AND FirstName = 'Robert'
Query 2:
SELECT * USER WHERE FirstName = 'Robert' AND LastName = 'Dupont'
Is there a difference ?
Thanks for your help !
The order of the comparisons does not matter. SQL Server should optimize the WHERE clause for the data.
However, if you care about performance, you should use an index, either user(firstname, lastname) or user(lastname, firstname). The order of comparisons is not the right thing to be thinking about.
an index of below form
(firstname,lastname)
Can help in both the queries..
firstname='' and lastname=''
or
lastname='' and fastname=''
so your both queries are faster,but when you issue query of below form ,with same index
firstname>='' and lastname=''
Firstname uses index and SQLServer can't use index on second column ,but it uses residual lookup to filter out values
Both query are same faster. Because 'where' clause includes conditions. That is not important unique columns .
it's exactly the same when both are on the same level. but this is definitely better:
SELECT *
FROM (SELECT *
FROM USER
WHERE LastName = 'Dupont')
WHERE FirstName = 'Robert'
EDIT
Going back to Relational Algebra, it's better to filter any results as far down the tree as possible. Assuming that last names are rarer than first names, you 1st filter the 'Duponts' and then look for the 'Roberts' in the result set.
Related
Which approach is better to get output of all the entries if the input is NULL or a specific record when input is NOT NULL?
This is for PL/SQL on Oracle Database. Let me know if my first approach is wrong
select * from student where (roll_no = :ROLL_NO or :ROLL_NO is NULL);
OR
select * from student where roll_no = NVL(:ROLL_NO, roll_no);
The two approaches will give different results where roll_no is null, because roll_no = roll_no will not be true for those rows.
If there is an index, the optimiser has a special case for somecol = nvl(:param,somecol), and you will see two FILTER operations and a CONCATENATION in the execution plan, representing the cases where :param is null or not null. Therefore I would use the nvl expression so long as roll_no is defined as a NOT NULL column.
In general, using operators is a better approach. This is because the optimizer can be smarter when the columns are not arguments to functions.
This answer assumes that roll_no is not null.
Although this could be a case that the Oracle optimizer sometimes catches, you might find that writing the query using union all actually produces a better execution plan when an appropriate index is present:
select s.*
from student s
where roll_no = :ROLL_NO
union all
select s.*
from student s
where :ROLL_NO is NULL;
Seconds approach would give same result with small modification(cannot compare null against null):
select * from student where NVL(roll_no,1) = NVL(NVL(:ROLL_NO, roll_no),1);
William Robertson made a good point. I understood my mistake then.
I tried the answer by Gordon linoff. It worked.
I think waldemort's answer will also be true, but i didn't try it.
This answer below is what was my solution for it and it might be similar to waldemort's answer.
{select * from student where AND (roll_no = nvl(roll_no,1) = nvl(:roll_no,1)}
Thanks for the help guys
The query I'd like to execute:
SELECT *
FROM qryReportView
WHERE ((ID = 719)
AND (Name Like "*x"));
However when I run this query I get no records returned. Each criterion works on its own:
SELECT *
FROM qryReportView
WHERE ID = 719;
and
SELECT *
FROM qryReportView
WHERE Name Like "*x";
Both queries return records as expected but when I combine them something goes wrong. I know there is at least one record for which both criteria are true.
NOTE: When I replace the * wildcard with an explicit name, I get the correct record returned. This is not a viable solution for me though because my query needs to select records ending in "x" with a number of possible prefixes.
Thank you so much for the help.
Your issue is a logical operator issue.
When you ask an RDBMs for a samich and a coke, if it has a samich but not a coke, you get nothing. Which is what is happening here, you need an 'or'
SELECT *
FROM qryReportView
WHERE (ID = 719
OR
Name Like '*x');
The problem is I have a table with 4 columns. I have two search boxes.
Fields
FName
LName
Age
School
Text boxes
FName
School
If the user has inserted two values I want to get the intersect using both values. If only one value is present I want to have data using that value. I thought of not handling this in the application but with a stored procedure.
I thought of using IF ELSE in the stored procedure or having sub queries. But not a solid solution. I need some guidance to think of a possible way. Thank you in advance.
Here is what I have tried. This is just the query I need to embed this in a stored procedure
SELECT * FROM STUDENT WHERE FNname like '%TestFName%'
INTERSECT SELECT * FROM STUDENT WHERE School LIKE '%TestSchool';
If the 'TestSchool" becomes null it takes all the records which full fill the first query.
If both values are missing it returns the whole table.
If both values are there it returns the specific data tuples.
Pretty sure it is as simple as this.
SELECT *
FROM STUDENT
WHERE FNname like '%TestFName%'
AND School LIKE '%TestSchool%';
If use 'AND' rather than 'OR' it meets all the given conditions
SELECT *
FROM YourTable
WHERE (FName = #Fname OR #Fname = '')
AND (School = #School OR #School ='')
Here is the answer I came up for my own problem.
SELECT * FROM STUDENT WHERE FNname like '%TestFName%'
INTERSECT SELECT * FROM STUDENT WHERE School LIKE '%TestSchool';
In here if the 'TestFName" becomes null it takes all the records which full fill the second query.
If the 'TestSchool" becomes null it takes all the records which full fill the first query.
If both values are missing it returns the whole table.
If both values are there it returns the specific data tuples.
Thank you. If there is a better way than this, please enlighten us.
You can use this :
SELECT * FROM STUDENT WHERE isnull(FNname, '') like '%' + isnull(#FNname, '') + '%'
and isnull(School, '') like '%' + isnull(#School, '') + '%'
Use the parameters #FNname and #School in your stored procedure and use the above query in it.
we have "Profile" table with over 60 columns like (Id, fname, lname, gender, profilestate, city, state, degree, ...).
users search other peopel on website. query is like :
WITH TempResult as (
select ROW_NUMBER() OVER(ORDER BY #sortColumn DESC) as RowNum, profile.id from Profile
where
(#a is null or a = #a) and
(#b is null or b = #b) and
...(over 60 column)
)
SELECT profile.* FROM TempResult join profile on TempResult.id = profile.id
WHERE
(RowNum >= #FirstRow)
AND
(RowNum <= #LastRow)
sql server by default use clustered index for execution query. but total execution time is over 300. we test another solution such as multi column index in all columns in where clause but total execution time is over 400.
do you have any solution to make total execution time lower than 100.
we using sql server 2008.
Unfortunately I don't think there is a pure SQL solution to your issue. Here are a couple alternatives:
Dynamic SQL - build up a query that only includes WHERE clause statements for values that are actually provided. Assuming the average search actually only fills in 2-3 fields, indexes could be added and utilized.
Full Text Search - go to something more like a Google keyword search. No individual options.
Lucene (or something else) - Search outside of SQL; This is a fairly significant change though.
One other option that I just remembered implementing in a system once. Create a vertical table that includes all of the data you are searching on and build up a query for it. This is easiest to do with dynamic SQL, but could be done using Table Value Parameters or a temp table in a pinch.
The idea is to make a table that looks something like this:
Profile ID
Attribute Name
Attribute Value
The table should have a unique index on (Profile ID, Attribute Name) (unique to make the search work properly, index will make it perform well).
In this table you'd have rows of data like:
(1, 'city', 'grand rapids')
(1, 'state', 'MI')
(2, 'city', 'detroit')
(2, 'state', 'MI')
Then your SQL will be something like:
SELECT *
FROM Profile
JOIN (
SELECT ProfileID
FROM ProfileAttributes
WHERE (AttributeName = 'city' AND AttributeValue = 'grand rapids')
AND (AttributeName = 'state' AND AttributeValue = 'MI')
GROUP BY ProfileID
HAVING COUNT(*) = 2
) SelectedProfiles ON Profile.ProfileID = SelectedProfiles.ProfileID
... -- Add your paging here
Like I said, you could use a temp table that has attribute name/values:
SELECT *
FROM Profile
JOIN (
SELECT ProfileID
FROM ProfileAttributes
JOIN PassedInAttributeTable ON ProfileAttributes.AttributeName = PassedInAttributeTable.AttributeName
AND ProfileAttributes.AttributeValue = PassedInAttributeTable.AttributeValue
GROUP BY ProfileID
HAVING COUNT(*) = CountOfRowsInPassedInAttributeTable -- calculate or pass in
) SelectedProfiles ON Profile.ProfileID = SelectedProfiles.ProfileID
... -- Add your paging here
As I recall, this ended up performing very well, even on fairly complicated queries (though I think we only had 12 or so columns).
As a single query, I can't think of a clever way of optimising this.
Provided that each column's check is highly selective, however, the following (very long winded) code, might prove faster, assuming each individual column has it's own separate index...
WITH
filter AS (
SELECT
[a].*
FROM
(SELECT * FROM Profile WHERE #a IS NULL OR a = #a) AS [a]
INNER JOIN
(SELECT id FROM Profile WHERE b = #b UNION ALL SELECT NULL WHERE #b IS NULL) AS [b]
ON ([a].id = [b].id) OR ([b].id IS NULL)
INNER JOIN
(SELECT id FROM Profile WHERE c = #c UNION ALL SELECT NULL WHERE #c IS NULL) AS [c]
ON ([a].id = [c].id) OR ([c].id IS NULL)
.
.
.
INNER JOIN
(SELECT id FROM Profile WHERE zz = #zz UNION ALL SELECT NULL WHERE #zz IS NULL) AS [zz]
ON ([a].id = [zz].id) OR ([zz].id IS NULL)
)
, TempResult as (
SELECT
ROW_NUMBER() OVER(ORDER BY #sortColumn DESC) as RowNum,
[filter].*
FROM
[filter]
)
SELECT
*
FROM
TempResult
WHERE
(RowNum >= #FirstRow)
AND (RowNum <= #LastRow)
EDIT
Also, thinking about it, you may even get the same result just by having the 60 individual indexes. SQL Server can do INDEX MERGING...
You've several issues imho. One is that you're going to end up with a seq scan no matter what you do.
But I think your more crucial issue here is that you've an unnecessary join:
SELECT profile.* FROM TempResult
WHERE
(RowNum >= #FirstRow)
AND
(RowNum <= #LastRow)
This is a classic "SQL Filter" query problem. I've found that the typical approaches of "(#b is null or b = #b)" & it's common derivatives all yeild mediocre performance. The OR clause tends to be the cause.
Over the years I've done a lot of Perf/Tuning & Query Optimisation. The Approach I've found best is to generate Dynamic SQL inside a Stored Proc. Most times you also need to add "with Recompile" on the statement. The Stored Proc helps reduce potential for SQL injection attacks. The Recompile is needed to force the selection of indexes appropriate to the parameters you are searching on.
Generally it is at least an order of magnitude faster.
I agree you should also look at points mentioned above like :-
If you commonly only refer to a small subset of the columns you could create non-clustered "Covering" indexes.
Highly selective (ie:those with many unique values) columns will work best if they are the lead colum in the index.
If many colums have a very small number of values, consider using The BIT datatype. OR Create your own BITMASKED BIGINT to represent many colums ie: a form of "Enumerated datatyle". But be careful as any function in the WHERE clause (like MOD or bitwise AND/OR) will prevent the optimiser from choosing an index. It works best if you know the value for each & can combine them to use an equality or range query.
While often good to find RoWID's with a small query & then join to get all the other columns you want to retrieve. (As you are doing above) This approach can sometimes backfire. If the 1st part of the query does a Clustred Index Scan then often it is faster to get the otehr columns you need in the select list & savethe 2nd table scan.
So always good to try it both ways & see what works best.
Remember to run SET STATISTICS IO ON & SET STATISTICS TIME ON. Before running your tests. Then you can see where the IO is & it may help you with index selection, for the mose frequent combination of paramaters.
I hope this makes sense without long code samples. (it is on my other machine)
I'm using the below query to return results from a table using Full-Text-Search.
In SQL2000 it was only possible to search one or all columns in a table. Is it possible in SQL 2008?
I would like to search two tables, Problem and Solution (Both indexed and in the same table):
DECLARE #topRank int set #topRank=(SELECT MAX(RANK)
FROM FREETEXTTABLE([Support_Calls], Problem, 'test', 1))
SELECT [ID] AS [Call No],Company_Name, Problem, Solution, CONVERT(VARCHAR(20),CAST((CAST(ftt.RANK as DECIMAL)/#topRank * 100) AS DECIMAL(13,0))) + '%' as Match
FROM [Support_Calls] INNER JOIN FREETEXTTABLE([Support_Calls], Problem, 'test') as ftt ON ftt.[KEY]=[ID] ORDER BY ftt.RANK DESC;
From what I can see the FREETEXTTABLE does not accept more than one column?
You specify them in parentheses; FREETEXTTABLE(tablename, (col1,col2,col3), 'expr') or use an asterisk to seach all columns in the index.
From MSDN,
Returns a table of zero, one, or more rows for those columns containing character-based data types for values that match the meaning, but not the exact wording, of the text in the specified freetext_string. FREETEXTTABLE can only be referenced in the FROM clause of a SELECT statement like a regular table name.
Queries using FREETEXTTABLE specify freetext-type full-text queries that return a relevance ranking value (RANK) and full-text key (KEY) for each row.
They give the following syntax:
FREETEXTTABLE (table , { column_name | (column_list) | * }
,'freetext_string'
[ , LANGUAGE language_term ]
[ ,top_n_by_rank ] )
So yes, what Alex K. said as well.
If you created a FULLTEXT INDEX on different columns, then you can simple use CONTAINS or FREETEXT to look on one of them, all of them, or some of them. Like this:
SELECT *
FROM YourTable
WHERE CONTAINS(*, #SearchTerm);
If you want to look on all the columns that are included in the FULLTEXT INDEX. or:
SELECT *
FROM YourTable
WHERE CONTAINS((ProductName, ProductNumber, Color), #SearchTerm);
If you want to specify the columns that you want to search. If you need the results in one column, you are gonna have to do a UNION and do a search for every column you want to be searched.
SELECT *
FROM YourTable
WHERE CONTAINS(ProductName, #SearchTerm)
UNION
SELECT *
FROM YourTable
WHERE CONTAINS(ProductNumber, #SearchTerm)
UNION
SELECT *
FROM YourTable
WHERE CONTAINS(Color, #SearchTerm)