I am a newbie to SQL server. keeping this question as reference.My doubt is
why Microsoft Sql server doesn't have something like limit in Mysql and now they are forcing to write either SP or inner query for pagination.I think creating a temporary view/table or using a inner query will be slower than a simple query.And i believe that there will be a strong reason for deprecating this. I like to know the reason.
If anyone know it please share it.
I never knew SQL Server supported something like TOP 10,20 - are you really totally sure?? Wasn't that some other system maybe??
Anyway: SQL Server 2011 (code-named "Denali") will be adding more support for this when it comes out by the end of 2011 or so.
The ORDER BY clause will get new additional keywords OFFSET and FETCH - read more about them here on MSDN.
You'll be able to write statements like:
-- Specifying variables for OFFSET and FETCH values
DECLARE #StartingRowNumber INT = 150, #FetchRows INT = 50;
SELECT
DepartmentID, Name, GroupName
FROM
HumanResources.Department
ORDER BY
DepartmentID ASC
OFFSET #StartingRowNumber ROWS
FETCH NEXT #FetchRows ROWS ONLY;
SQL Server 2005 Paging – The Holy Grail (requires free registration).
(Although it says SQL Server 2005 it is still applicable to SQL Server 2008)
I agree 100%! MySQL has the LIMIT clause that makes a very easy syntax to return a range of rows.
I don't know for sure that temporary table syntax is slower because SQL Server may be able to make some optimizations. However, a LIMIT clause would be far easier to type. And I would expect there would be more opportunities for optimization too.
I brought this once before, and the group I was talking to just didn't seem to agree.
As far as I'm concerned, there is no reason not to have a LIMIT clause (or equivalent), and I strongly suspect SQL Server eventually will!
Related
I can't find an easy way to make paging for complex queries for SQL server. I need to write function that takes sql query as an argument (this query can include subqueries, order by statements, grouping etc.) and retrieve a particular page of results. In oracle it's easy by encapsulating such query with another select statement, but for SQL server I can't find any simillar way. What I would like to avoid is to parse input SQL statement. I'm using SQL server 2005
Paging in SQL Server 2005 and upwards is best done via ranking functions. However, given that an arbitrary SQL query is unsorted, you need to somehow specify what the sort shall be for this to work, which isn't really "compatible" with a generic solution like you're trying to make (*).
The suggested way to do it is like this (assuming the variables #PageSize with the number of items per page, and #Page as 1-based index to the page you want to retrieve):
WITH NumberedQuery AS (
SELECT ROW_NUMBER() OVER (ORDER BY q.SomeColumn) ix, q.*
FROM QueryToPage q
)
SELECT nq.*
FROM NumberedQuery nq
WHERE (nq.ix >= (#Page-1)*#PageSize) AND (nq.ix < #Page*#PageSize);
(*): Your approach with concatenating SQL code has several issues, it prevents the use of parametrized queries, it adds the risk of SQL injection, it hurts performance and it cannot solve the issue at hand if the order is unspecified.
We're currently testing our app from SQL Server 2000 to 2008R2.
The following statement works in 2000, and not in 2008.
select distinct left(tz.Zipcode,5) as zipCode
from TerritoryZip tz
order by tz.Zipcode
The error message is:
Msg 145, Level 15, State 1, Line 1
ORDER BY items must appear in the select list if SELECT DISTINCT is specified.
The fix is simple:
select distinct left(tz.Zipcode,5) as zipCode
from TerritoryZip tz
order by left(tz.Zipcode,5)
However there is a risk that we may not find all the instances of this type of SQL.
So one solution might be to set the compatibility level to 2000 - what are the cons of doing that (e.g. performance of not updating the SQL to use this more strict approach)?
And are there other options/settings, e.g. is there a 'strictness' setting that is enforcing better practices, etc...?
Thanks!!
You could change the semantics slightly by doing this:
SELECT ZipCode FROM
(
SELECT DISTINCT ZipCode = LEFT(tz.Zipcode, 5)
FROM dbo.TerritoryZip
) AS x
ORDER BY ZipCode;
Doesn't solve the problem really since the query is more verbose and you still can't avoid touching it. The fix you've already suggested is better in my mind because it is more explicit about what is going on.
Not to be harsh, but if you don't think you'll be able to "find all the instances of this type of SQL" then how are you trusting your testing at all?
I would suggest that keeping 2000 mode is not the optimal answer. The reason is this can cause other syntax to break (e.g. the way you might call dynamic management functions - see this Paul Randal blog post and my comment to it), you also run the risk of perpetuating code that should be fixed (e.g. old-style *= / =* joins that are valid in 2000 compat mode, but won't be valid when you go from 2008 R2 -> Denali, which doesn't support 2000 compat).
There is no "strictness" setting but you can vote for Erland Sommarskog's SET STRICT_CHECKS ON; suggestion.
So one solution might be to set the compatibility level to 2000 - what
are the cons of doing that (e.g. performance of not updating the SQL
to use this more strict approach)?
I suggest you look at the documentation on ALTER DATABASE Compatibility Level (Transact-SQL) which lists dozens of differences between the compatibility levels along with the Possibility of impacts of low medium and high.
Also you should probably run the Upgrade Advisor which looks through your components for potential problems that you would need to fix
MSDN has a really good article showing the differences between different compatibility levels in SQL Server 2008 (including performance notes and best practices): http://msdn.microsoft.com/en-us/library/bb510680.aspx. Even in the example you gave, the SQL in the 2008 version is more intuitive and is enforcing a better best practice.
This question has been asked before -
How we can use CTE in subquery in sql server?
The only answer suggested was "Just define your CTE on top and access it in the subquery?"
This works, but I would really like to be able to use a CTE in the following scenarios -
as a subquery in a SELECT
as a derived table in the FROM clause of a SELECT
Both of these work in PostgreSQL. With Sql Server 2005, I get "Incorrect syntax near the keyword 'with'".
The reason I would like it is that most of my queries are constructed dynamically, and I would like to be able to define a CTE, save it somewhere, and then drop it in to a more complex query on demand.
If Sql Server simply does not support this usage, I will have to accept it, but I have not read anything that states that it is not allowed.
Does anyone know if it is possible to get this to work?
In SQL Server, CTE's must be at the top of the query. If you construct queries dynamically, you could store a list of CTE's in addition to the query. Before you send the query to SQL server, you can prefix the query with a list of CTE's:
; with Cte1 as (...definition 1...),
Cte2 as (...definition 2...),
Cte3 as (...definition 3...),
...
...constructed query...
This is assuming that you're constructing the SQL outside of SQL Server.
You could also consider creating views. Views can contain CTE's, and they can be used as a subquery or derived table. Views are a good choice if you generate SQL infrequently, say only during an installation or as part of a deployment.
SQL Server does not support this much-required feature. I too have been looking for help on this.
MS SQL Server does not support Temporary Views either as opposed to PostgreSQL. The above-mentioned solution is also likely to work only if all the CTE definitions could be generated before-hand and do not have conflicting names in each of the sub-queries either - the purpose being that these CTE definitions may be different for each level of a sub-query.
Sad but true !!!
Regards,
Kapil
We just upgraded our SQL Server 2005 to SQL server 2008 R2 and noticed some performance problems.
The query below was already slow but now in 2008 it just times out. We rebuild the catalog to make sure its freshly made on 2008
DECLARE #FREETEXT varchar(255) = 'TEN-T'
select Distinct ...
from
DOSSIER_VERSION
inner join
DOSSIER_VERSION_LOCALISED ...
where
CONTAINS(DOSSIER_VERSION.*,#FREETEXT)
or
CONTAINS(DOSSIER_VERSION_LOCALISED.*,#FREETEXT)
The query takes minutes if you have both conditions enabled.
If you just put the following in the where
CONTAINS(DOSSIER_VERSION.*,#FREETEXT)
Its super fast. Same goes for the case if its just
CONTAINS(DOSSIER_VERSION_LOCALISED.*,#FREETEXT)
Since we are or'ing the results I would expect the time for this query to run to be less than the sum but as stated above it takes minutes/times out.
Can anyone tell me what is going on here? If I use a union (which is conceptually the same as the or) the performance problem is gone but I would like to know what issue I am running into here since I want to avoid rewriting queries.
Regards, Tom
See my answers to these very similar questions:
Adding more OR searches with
CONTAINS Brings Query to Crawl
SQL Server full text query across
multiple tables - why so slow?
The basic idea is that using LEFT JOINs to CONTAINSTABLE (or FREETEXTTABLE) performs significantly better than having multiple CONTAINS (or FREETEXT) ORed together in the WHERE clause.
I've a table with a lot of registers (more than 2 million). It's a transaction table but I need a report with a lot of joins. Whats the best practice to index that table because it's consuming too much time.
I'm paging the table using the storedprocedure paging method but I need an index because when I want to export the report I need to get the entire query without pagination and to get the total records I need a select all.
Any help?
The SQL Server 2008 Management Studio query tool, if you turn on "Include Actual Execution Plan", will tell you what indexes a given query needs to run fast. (Assuming there's an obvious missing index that is making the query run unusually slow, that is.)
SQL Server 2008 Management Studio Query Screenshot http://img208.imageshack.us/img208/4108/image4sy8.png
We use this all the time on Stack Overflow.. one of the best features of SQL 2008. It works against older SQL instances as well, just install the SQL 2008 tools and point them at a SQL 2005 instance. Not sure if it works on anything earlier, though.
As others have noted, you can also do this manually, but it takes a bit of trial and error. You'll want indexes on fields that are used in ORDER BY and WHERE clauses.
key fields have to be everithing in
the where clause ???
No, that would be overkill. Indexing a field really only works if a) your WHERE clause is selective enough (that is: only selects out about 1-2% of the values; an index on a "Gender" field which can be only one of two or three possible values is pointless), and b) your WHERE clause doesn't involve function calls or other magic.
In your case, TBL.Status might be a candidate - how many possible values are there? You select the '1' and '2' value - if there are hundreds of possible values, then it's a good choice.
On a side note:
this clause here: (TBL.Login IS NULL AND TBL.Login <> 'dev' ) is pretty pointless - if the value of TBL.login IS NULL, then it's DEFINITELY not 'dev' ..... so just the "IS NULL" will be more than sufficient......
The other field you might want to consider putting an index on is the TBL.Date, since you seem to select a range of dates here - that might be a good choice.
Also, on a general note: whenever possible, DO NOT use a SELECT * FROM ...... to select your fields. This causes a lot of overhead for SQL Server. SPECIFY your columns - and ONLY select those that you REALLY NEED - not just all of them for the heck of it.....
Check your queries, and find which fields are used to match them. Those are usually the best candidates!
SQL Server has a 'Database Engine Tuning Advisor' that could help you. This does not exist for SQL Server Express, but does for all other versions of SQL Server.
Load your query in a query window.
On the menu, click Query -> Analyze Query in Database Engine
Tuning Advisor
The tuning advisor will identify indexes that could be added to your table(s) to improve performance. In my experience, the tuning advisor doesn't always help, but most of the time it does. It's where I suggest you start.
ok this is the query in doing
SELECT
TBL.*
FROM
FOREINGDATABASE..TABLENAME TBL
LEFT JOIN Status S
ON TBL.Status = S.Number
WHERE
(TBL.ID = CASE #Reference WHEN 0 THEN TBL.ID ELSE #Reference END) AND
TBL.Date >= #FechaInicial AND
TBL.Date <= #FechaFinal AND
(TBL.Channel = CASE #Canal WHEN '' THEN TBL.Channel ELSE #Canal END)AND
(TBL.DocType = CASE #TipoDocumento WHEN '' THEN TBL.DocType ELSE #TipoDocumento END)AND
(TBL.Document = CASE #NumDocumento WHEN '' THEN TBL.Document ELSE #NumDocumento END)AND
(TBL.Login = CASE #Login WHEN '' THEN TBL.Login ELSE #Login END)AND
(TBL.Login IS NULL AND TBL.Login <> 'dev' ) AND
TBL.Status IN ('1','2')
key fields have to be everithing in the where clause ???
If I am not mistaken, please correct me if I am, I think you should create non-clustered Index on the fields of the conditions of the where clause. (Maybe this can be useful as a starting point to get some candidates for the indexes).
Good Luck
if an Index Scan instead of a seek is performed, the cause might be that the fields are not in the correct order in the index.
put indexes on all columns that you're joining and filtering on.
the use of indexes is also determined by the selectivity of the indexed column.
the best way would be to show us your query so we can try to improve it.