SQL Server专家...
当前正在使用MS SQL Server 2016
我知道Joe Celko和所有SQL纯粹主义者都在考虑使用位掩码,但是我有一个用例,其中我需要查询包含一组给定属性的所有小部件。
我认为做到这一点的一种方法是通过位掩码-可以将要找到的属性(位掩码)与每个小部件的属性进行“与”操作,以在单个操作中找到匹配项。例如,小部件表可能是:
widets table:
widget_uid Uniqueidentifier
attributes BigInt
SELECT widget_uid
FROM widgets
WHERE ( attributes & bitmask ) = bitmask;
问题是,使用BigInt作为属性将属性数量限制为64(一个小部件可以具有数百个属性),我可以将属性分组为64位的块,即:
widets table:
widget_uid Uniqueidentifier
attributes0 BigInt -- Attributes 0-63
attributes1 BigInt -- Attributes 64-127
attributes2 BigInt -- Attributes 128-191
SELECT widget_uid
FROM widgets
WHERE ( attributes0 & bitmask0 ) = bitmask0
AND ( attributes1 & bitmask1 ) = bitmask1
AND ( attributes2 & bitmask2 ) = bitmask2
...但是想知道是否有人提出了使用大于64位的位掩码进行位操作的解决方案–还是会存在其他(更有效的?)解决方案?
在用例中,widgets表确实包含其他列,但是我现在只关心查询的属性匹配部分。
欢迎任何想法-希望了解其他人如何解决这个特定问题。
谢谢。
答案 0 :(得分:0)
我们在大量数据集上有一个类似的用例。这是针对具有产品和属性的电子商务网站。我们的情况比这里要复杂一些,这里我们有任意数量的属性,然后为这些属性分配了值。例如颜色-红色/绿色/蓝色,尺寸-S / M / L等
在我们的案例中,我们发现具有良好索引的关联表是关键。虽然这可能不是您的选择,但我们发现这是动态数据集的最佳解决方案。
如果您觉得有帮助,我可以为您编写示例。
编辑后添加示例: 如果存在#DROP TABLE 如果存在#DROP TABLE 如果存在表#WidgetAttributes
CREATE TABLE #Widgets (widget_UID UNIQUEIDENTIFIER PRIMARY KEY CLUSTERED, Name NVARCHAR(255))
CREATE TABLE #Attributes (Attribute_UID UNIQUEIDENTIFIER PRIMARY KEY CLUSTERED, Name NVARCHAR(255))
CREATE TABLE #WidgetAttributes (widget_UID UNIQUEIDENTIFIER,Attribute_UID UNIQUEIDENTIFIER)
CREATE NONCLUSTERED INDEX ix_WidgetAttribute ON #WidgetAttributes (Attribute_UID) INCLUDE (widget_UID)
INSERT INTO #Widgets (widget_UID, Name) values
( '{c63bea73-2331-4698-82c9-f71845ab8601}', N'Widget 1' ),
( '{a0865b8f-606b-4273-9207-39a8a26016c4}', N'Widget 2' ),
( '{211fe27e-ab98-4b61-83a3-3d006d66db5a}', N'Widget 3' )
INSERT INTO #Attributes (Attribute_UID, Name)
VALUES
( '{99354dc0-d0b2-4919-a887-edf115eeb1bd}', N'Height' ),
( '{136bbe4c-497d-472f-a905-670e4a7805d0}', N'Width' ),
( '{f006f950-30d1-453e-8e09-4f7d140fa3cb}', N'Depth' ),
( '{0d190639-677f-4b75-8d36-1bdac00de132}', N'Colour' )
-- Set links
-- Widget 1 All attributes
-- Widget 2 Height Width
-- Widget 3 Colour
INSERT INTO #WidgetAttributes (widget_UID, Attribute_UID)
SELECT '{c63bea73-2331-4698-82c9-f71845ab8601}',Attribute_UID FROM #Attributes
UNION ALL
SELECT TOP (2) '{a0865b8f-606b-4273-9207-39a8a26016c4}',Attribute_UID FROM #Attributes WHERE Name<> 'Colour'
UNION ALL
SELECT '{211fe27e-ab98-4b61-83a3-3d006d66db5a}',Attribute_UID FROM #Attributes WHERE Name = 'Colour'
-- @SearchAttributes to hold list of attributes you are trying to find
DECLARE @SearchAttributes TABLE (Attribute_UID UNIQUEIDENTIFIER)
INSERT INTO @SearchAttributes
SELECT Attribute_UID FROM #Attributes WHERE Name<> 'Colour'
;WITH cte AS (
SELECT WA.widget_UID, COUNT(1) AttributesPresent FROM #WidgetAttributes WA
JOIN @SearchAttributes SA ON SA.Attribute_UID = WA.Attribute_UID
GROUP BY WA.widget_UID
)
SELECT cte.AttributesPresent
, W.widget_UID
, W.Name
FROM cte
JOIN #Widgets W ON W.widget_UID = cte.widget_UID
ORDER BY cte.AttributesPresent DESC
给出以下输出:
AttributesPresent widget_UID Name
----------------- ------------------------------------ ----------
3 C63BEA73-2331-4698-82C9-F71845AB8601 Widget 1
2 A0865B8F-606B-4273-9207-39A8A26016C4 Widget 2
我们使用一种计算每种属性存在多少个属性的方法,因此我们不仅可以选择“完全匹配”,还可以选择“最接近”。
答案 1 :(得分:0)
在数据库中使用位掩码是错误的方法。即使您以某种方式对其进行管理,也将无法使用索引来加快执行速度。
使用标准溶液,这是标准情况。窗口小部件和属性之间存在标准的M:N关系(当然,两者都应该是表)。您将添加另一个将属性分配给Widget的表-您可以将其称为WidgetAttributes。
它将具有3列:Id,WidgetId,AttributeId
然后您可以简单地获取具有属性的小部件的列表:
select w.*
from Widgets w
inner join WidgetAttributes wa on wa.WidgetId = w.Id
inner join Attributes a on a.Id = wa.AttributeId
where a.AttributeName='xxx'