Query optimization of tree hierarchical data in SQL

Source: Internet
Author: User

In a data query, starting with 2008, SQL Server provides a new data type, HierarchyID, specifically for manipulating hierarchical data structures.

The HierarchyID type logically encodes information about a single node in the hierarchy tree by encoding the path from the root of the tree to the node.

This path is logically represented as a sequence of node labels for all children that are accessed after the root. The representation begins with a slash, and the path that accesses the root only is represented by a single slash. For levels below the root, each label is encoded as a sequence of integers separated by points. The comparison between the children is to compare the sequence of integers separated by points in dictionary order. A slash follows each level. Therefore, the slash separates the parent from its children. For example, the following are valid HierarchyID paths with lengths of 1, 2, 2, 3, and 3, respectively:

? /

? /1/

? /0.3.-7/

? /1/3/

? /0.1/0.2/

In the days when there was no hierarchyid, we queried the parent and all the subordinates in the way of the CTE, but the way the CTE would be very slow in the case of a lot of data, we later built the path to speed it up. Then, with the HierarchyID type, it's natural to use HierarchyID.

Now, let's look at the power of HierarchyID by a practical example.

One: CTE method

With Ctegetchild as
(
SELECT * from el_organization.organization WHERE id= ' ecc43c7159924dca91e2916368f923f4 '--and [state]=0 and AuditState=2
UNION All
(
SELECT a.* from El_organization.organization as A
INNER JOIN Ctegetchild as B on A.parentid=b.id--and a.[state]=0 and a.auditstate=2
)
)

query out 4489 lines, need 25S.

It seems that the CTE has reached a point where it is intolerable, so now we use it to optimize.

Two: HierarchyID

First, we need to create the field and assign it a value.

Create function F_cidname (@id varchar) returns varchar (max) as
Begin
declare @pids nvarchar (max);
declare @pNames nvarchar (max);
Set @pids = ';
Set @pNames = ';
With CTE as
(select Id,parentid,name from el_organization.organization where ID [email protected] ' 00037fdf184e48d084b87c3499e3c0e5 '
UNION ALL
Select B.id,b.parentid,b.name from CTE A, el_organization.organization b where A.parentid = b.ID
)

Select @pids =convert (varchar), convert (int, convert (varbinary (max), id)) + '/' + @pids from CTE
Return '/' [email protected]

End
Go

Next, we need to update the entire table:

UPDATE el_organization.organization SET pids=dbo.f_cidname (ID)

Note that the ID is a 32-bit string of GUIDs, and the HierarchyID field does not support the path within that size, so we convert the GUID to integer: convert (varchar), convert (int, convert ( varbinary (max), id)))

2.1 TIP

Exception Message:DataReader.GetFieldType (4) returned null. Exception data:System.Collections.ListDictionaryInternal

Note that it is very likely that we have updated the field and our program has gone wrong, as above. This time, we need to put

C:\Program Files\Microsoft SQL Server\100\SDK\Assemblies\Microsoft.SqlServer.Types.dll

This DLL is packaged into our application. The reason is not explained.

Look at the effect, the modified code is:

DECLARE @tmpIds HierarchyID
SELECT @tmpIds =pids from el_organization.organization WHERE id= ' ecc43c7159924dca91e2916368f923f4 ';
With Ctegetchild as (
SELECT * from el_organization.organization WHERE id= ' Ecc43c7159924dca91e2916368f923f4 '
UNION All (
SELECT * from El_organization.organization WHERE pids.isdescendantof (@tmpIds) =1
)
)
SELECT * from Ctegetchild

Now, our time is within 1S.

2.2 Everything in order to not move the application layer code

Now, since we have added a field, we need to maintain this field, such as: This record is moved to a different parent in the application, and this field needs to be updated. In order to not move the upper code, the only thing to do is to create a trigger, namely: The original ParentID changes, you need to update the PIDs field, so we create a trigger as follows:

Create Trigger Updateorgpids
On El_organization.organization
After update
As
If update ([ParentID])
Begin
DECLARE @tmpId varchar (36)
Select @tmpId =id from inserted
Update el_organization.organization set Pids=dbo.f_cidname (@tmpId)
End
Go
--Drop Trigger El_organization.updateorgpids

Sweep, follow the most lessons, get a daily workout

Query optimization of tree hierarchical data in SQL

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.