在过去的几天里,我一直在阅读一本关于数据结构的电子书,坦率地说,很多事情已经从我的头脑中消失了。只是审查它们并试图再次澄清。我正在浏览哈希表并再次熟悉它。所以我知道并且听说过,SQL Server在内部使用散列表,stackoverflow.com和forums.asp.net的许多线程询问在SQL Server中存储临时数据时是否创建散列表。因此,让我举一个我在使用临时表的存储过程中使用的示例:(避免它并且它太长了。仅举例)
第一
CREATE PROCEDURE [dbo].[Orders]
@OrderLine int
AS
BEGIN
DECLARE @t1 TABLE(Date1 date,
OrderID VARCHAR(MAX),
EmployeeName VARCHAR(MAX),
DeliveryDate date,
StoreName VARCHAR(MAX),
DeliveryAddress VARCHAR(MAX),
ItemName VARCHAR(MAX),
Quantity FLOAT)
INSERT INTO @t1(Date1, OrderID, EmployeeName, DeliveryDate, StoreName, DeliveryAddress, ItemName, Quantity)
(SELECT DISTINCT
CONVERT(VARCHAR(11), DemandOrder.POCreationDate, 6) AS DemandOrderDate,
DemandOrder.OrderID, EmployeeDetails.EmployeeName,
CONVERT(DATE, DemandOrder.DeliveryDate) AS ExpectedDeliveryDate,
StoreDetails.StoreName,
DemandOrder.DeliveryAddress, Item.ItemName,
DemandOrderLine.Quantity
FROM
DemandOrder
INNER JOIN
DemandOrderLine ON DemandOrder.OrderID = DemandOrderLine.OrderID
INNER JOIN
Item on DemandOrderLine.ItemID=Item.ItemID
INNER JOIN
EmployeeDetails ON EmployeeDetails.EmployeeID = DemandOrder.EmployeeID
INNER JOIN
StoreDetails ON DemandOrderLine.StoreID = StoreDetails.StoreID
WHERE
DemandOrderLine.OrderLine = @OrderLine)
DECLARE @t2 TABLE(Approvedby VARCHAR(MAX))
INSERT INTO @t2(Approvedby)
(SELECT EmployeeDetails.EmployeeName
FROM EmployeeDetails
INNER JOIN DemandOrderLine ON DemandOrderLine.ApprovedBy = EmployeeDetails.EmployeeID)
SELECT DISTINCT
CONVERT(VARCHAR(11), Date1, 6) AS Date,
OrderID, EmployeeName,
CONVERT(VARCHAR(11), DeliveryDate, 6) AS ExpectedDeliveryDate,
StoreName, Approvedby, DeliveryAddress,
ItemName, Quantity
FROM
@t1
CROSS JOIN
@t2
END
另一个例子,在存储过程中说,哈希表不能使用。所以在这里:
第二
CREATE PROCEDURE TempTable AS ---- It's actually not possible in SP
CREATE table #Color
(
Color varchar(10) PRIMARY key
)
INSERT INTO #color
SELECT 'Red'
UNION
SELECT 'White'
UNION
SELECT 'green'
UNION
SELECT 'Yellow'
UNION
SELECT 'blue'
DROP TABLE #color
CREATE table #Color
(
Color varchar(10) PRIMARY key
)
INSERT INTO #color
SELECT 'Red'
UNION
SELECT 'White'
UNION
SELECT 'green'
UNION
SELECT 'Yellow'
UNION
SELECT 'blue'
DROP TABLE #color
GO
所以我的问题是,我可以说第一个是哈希表的一个例子,因为它使用临时表,如果没有,为什么我们不能在存储过程中使用它?同样,如果它是在内部创建的,为什么我们需要再次创建一个哈希表用于工作目的(虽然它有性能问题,只是想知道上面的例子是否用于此目的)。感谢。
注意:我上个月接受了一次采访,正在讨论这个问题。这就是为什么要确定我的观点是否正确。
答案 0 :(得分:5)
评论太长了。
基于哈希的算法对于任何强大的数据库都很重要。这些用于聚合和连接操作。自7.0版本以来,基于哈希的连接已经存在 - 这真的很旧(感谢Martin Smith)。您可以在documentation。
中详细了解它们SQL Server 2014为内存优化表引入了基于哈希的索引(请参阅here)。这些是哈希表的显式使用。但是,一般而言,基于树的索引更强大,因为它们可以在更多情况下使用:
like
)。order by
。哈希索引只能用于完全相等的匹配(和group by
)。
答案 1 :(得分:2)
我知道聚会晚了一点,但是我认为没有人直接回答过你原来的问题。
第一个是表变量的示例,第二个是本地表的示例,两者均在tempdb中创建
它们之间的区别在于,表变量不是在内存中创建的,并且不能具有聚集索引。 同样,本地(哈希)表将一直存在,直到单个连接结束,而表变量仅可用于声明其的批处理。 全局表(在其前使用双哈希)将对所有连接可用,并一直存在,直到关闭所有使用它的连接。
最后一件事情,您不能在存储过程中使用该本地表的唯一原因是因为它使用了两次相同的名称,即使您已经使用了drop table,它也会首先基于批处理中的创建对其进行评估。因此,它不会执行任何操作并抱怨它已经存在。
答案 2 :(得分:1)
请注意以下注释作为扩展注释,而不是单独的答案:
[1] SQL Server已加入(INNER HASH JOIN
)和查询提示(OPTION (HASH JOIN)
,OPTION(HAS GROUP')
),以强制执行此类物理连接或分组。
[2]在内部,SQL Server使用哈希表作为锁标识符。请参阅未记录的函数%% lockres %%(ref。http://www.sqlskills.com/blogs/paul/investigating-locking-and-deadlocking-with-lockres/)。
USE tempdb
GO
CREATE TABLE dbo.Documents (
ID INT IDENTITY(1,1) PRIMARY KEY,
DocDate DATE NOT NULL,
Content VARCHAR(8000) NOT NULL
);
CREATE INDEX IX_Documents_DocDate
ON dbo.Documents (DocDate)
GO
INSERT dbo.Documents (DocDate, Content)
VALUES
('2016-01-01', REPLICATE(CONVERT(VARCHAR(MAX), 'A'), 4000)),
('2016-02-02', REPLICATE(CONVERT(VARCHAR(MAX), 'B'), 5000)),
('2016-03-04', REPLICATE(CONVERT(VARCHAR(MAX), 'C'), 6000));
GO
SELECT ID, DocDate, %%lockres%% AS record_lock_hash
FROM dbo.Documents WITH(INDEX=1) -- Clustered index
GO
/*
ID DocDate record_lock_hash
----------- ---------- --------------------------------
1 2016-01-01 (8194443284a0)
2 2016-02-02 (61a06abd401c)
3 2016-03-04 (98ec012aa510)
*/
GO
SELECT ID, DocDate, %%lockres%% AS record_lock_hash
FROM dbo.Documents WITH(INDEX=IX_Documents_DocDate) -- Non-Clustered index
GO
/*
ID DocDate record_lock_hash
----------- ---------- --------------------------------
1 2016-01-01 (417e1de8c3fb)
2 2016-02-02 (6aede25aab61)
3 2016-03-04 (e701c6578164)
*/
GO
[3]作为数据库开发人员,我使用“哈希表”(使用哈希函数定义的计算列)来索引大文本(或blob):
ALTER TABLE dbo.Documents
ADD ContentHash AS CHECKSUM(HASHBYTES('sha256', Content)) /*PERSISTED*/ -- Computed column
GO
SET ANSI_NULLS, QUOTED_IDENTIFIER ON
GO
SET ANSI_WARNINGS, ANSI_PADDING, ARITHABORT, CONCAT_NULL_YIELDS_NULL ON
SET NUMERIC_ROUNDABORT OFF
GO
CREATE INDEX IX_Documents_ContentHash
ON dbo.Documents (ContentHash)
--INCLUDE (Content)
GO
DECLARE @ParamContent VARCHAR(8000) = REPLICATE(CONVERT(VARCHAR(MAX), 'B'), 5000)
DECLARE @ParamHash INT = CHECKSUM(HASHBYTES('sha256', @ParamContent))
SELECT d.ID, d.Content
FROM dbo.Documents d WITH(FORCESEEK)
WHERE d.ContentHash = @ParamHash -- Index Seek Predicate (Fast/optimized if there is an index on ContentHash computed column)
AND d.Content = @ParamContent -- [Simple / non-indexed] Predicate (Slow)
GO
注意:indexing computed columns时请注意(请参阅SET
的要求)。
答案 3 :(得分:0)
DECLARE @SEPERATOR as VARCHAR(1)
DECLARE @SP INT
DECLARE @VALUE VARCHAR(MAX)
SET @SEPERATOR = ','
CREATE TABLE #TempCode (id int NOT NULL)
/**this Region For Storing SiteCode**/
WHILE PATINDEX('%' + @SEPERATOR + '%', @Code ) <> 0
BEGIN
SELECT @SP = PATINDEX('%' + @SEPERATOR + '%' ,@Code)
SELECT @VALUE = LEFT(@Code , @SP - 1)
SELECT @Code = STUFF(Code, 1, @SP, '')
INSERT INTO #TempCode (id) VALUES (@VALUE)
END