Thanks so much for the feedback on our first Technical Preview. It's great to see people engaging with the bits at such a detailed level and the feedback we've gotten thus far has been spot on and extremely constructive. We've been hard at work digesting all the suggestions and turning them into a design changes. Here's the set of changes that we've come up with for our February CTP.
API Names
First, we've gotten some strong feedback that that the _stmt and _conn in the API names are not necessary, so we will be removing these to make the names more concise. This table summarizes the changes (you may notice other changes to the signatures – they're discussed in detail below):
http://statisticsio.com/Feeds/SQLBlogfeeds/tabid/60/Default.aspx -2/19/2008 9:10:00 PM
Recursive CTEs always follow the same pattern. The body of the CTE is a UNION ALL query that combines one or more anchor sub-selects which seed the result set and one or more recursive sub-selects which generate the remainder of the result set. The recursive sub-selects reference the recursive CTE itself.
Let's look at a simple example which computes a list of all employees and their level within the organization. Computing the level with the organization can only be done using a recursive CTE as it requires counting the number of joins required to reach each employee:
WITH DirectReports(ManagerID, EmployeeID, EmployeeLevel) AS ( SELECT ManagerID, EmployeeID, 0 AS EmployeeLevel FROM HumanResources.Employee WHERE ManagerID IS NULL UNION ALL&n
In some of my past posts, I've discussed how SQL Server implements aggregation including the stream aggregate and hash aggregate operators. I also used hash aggregation as an initial example in my introductory post on parallel query execution. In this post, I'll look at a partial aggregation. Partial aggregation is a technique that SQL Server uses to optimize parallel aggregation. Before I begin, I just want to note that I also discuss partial aggregation in Inside Microsoft SQL Server 2005: Query Tuning and Optimization. (See the bottom of page 187.)
Let's begin with a simple scalar aggregation example. Recall that a scalar aggregate is an aggregate without a GROUP BY clause. A scalar aggregate always produces a single output row.
CREATE TABLE T (A INT, B INT IDENTITY, C INT,
It’s great to see that people are downloading our the February CTP build of our PHP driver and that we’re getting feedback on our new features. We look forward to more of your feedback and we’re in the process of setting up a new forum specifically for questions and feedback for the PHP driver.
A lot of the feedback has centered around requests for a num_rows function for the PHP driver. In our PHP driver, we’re using the most performant way to retrieve the results of a SQL Server query, a forward-only read-only stream of data. With this approach there’s no way for the driver to know how the total number of rows that the query will return until you’ve finished processing the results of the query. We could offer a num_rows function but without providing buffered resultsets, that num_rows function would only return the number of rows returned so far. While that appears to be a fairly standard behavior for drivers that don’t support buffered resultsets, it doesn’t strike me as adding a great deal of value. With that said, I’m curious as to whether there’s real interest in a num_rows function without adding support for buffered resultsets?
We are planning on adding a function to return the number of fields in a resultset later in this release. Th
SQL Server 2005 introduced four new functions, ROW_NUMBER, RANK, DENSE_RANK, and NTILE that are collectively referred to as ranking functions. These functions differ from ordinary scalar functions in that the result that they produce for a given row depends on the other rows in the result set. They also differ from aggregate functions in that they produce exactly one output row for each input row. Unlike aggregates they do not collapse a set of rows into a single row. In this post, I'll take a look at ROW_NUMBER - the simplest of all ranking functions.
I'll use the following simple data set for the examples in this post:
CREATE TABLE T (PK INT IDENTITY, A INT, B INT, C INT)CREATE UNIQUE CLUSTERED INDEX TPK ON T(PK)INSERT T VALUES (0, 1, 8)INSERT T VALUES (0, 3, 6)INSERT T VALUES (0, 5, 4)INSERT T VALUES (0, 7, 2)INSERT T VALUES (0, 9, 0)INSERT T VALUES (1, 0, 9)INSERT T VALUES (1, 2, 7)INSERT T VALUES (1, 4, 5)INSERT T VALUES (1, 6, 3)INSERT T VALUES (1, 8, 1)
CREATE TABLE T (PK INT IDENTITY, A INT, B INT, C INT)CREATE UNIQUE CLUSTERED INDEX TPK ON T(PK)
INSERT T VALUES (0, 1, 8)INSERT T VALUES (0, 3, 6)INSERT T VALUES (0, 5, 4)INSERT T VALUES (0, 7, 2)INSERT T VALUES (0, 9, 0)INSERT T VALUES (1, 0, 9)INSERT T VALUES (1, 2, 7)INSERT T VALUES (1, 4, 5)INSERT T VALUES (1, 6, 3)INSERT T VALUES (1, 8, 1)
Let's begin with the following simple example:
SELECT *, ROW_NUMBER() OVER (ORDER BY B) AS RowNumber FROM T
This query orders the rows in the table by column B and assigns sequential row numbers (much like an identity column) to these rows. The result looks like so:
PK A B C RowNumber ----- ----- ----- ----- ---------- 6 1 0 9 1 1 0 1 8 2 7 1 2 7 3 2 0 3 6 4 8 1 4 5 5 3 0 5 4 6 9 1 6 3 7 4 0 7 2 8 10 1 8 1 9 5 0 9 0 10
The plan for this query is fairly simple:
|--Sequence Project(DEFINE:([Expr1003]=row_number)) |--Compute Scalar(DEFINE:([Expr1005]=(1)))