交叉加入需要太长时间

时间:2014-11-10 18:10:30

标签: sql sql-server database

请参阅下面的DDL:

CREATE TABLE [dbo].[TBX_RRDGenieDeletedItem](
    [DeletedId] [decimal](25, 0) NOT NULL
) ON [PRIMARY]

INSERT INTO TBX_RRDGenieDeletedItem values (90309955000010401948421)

CREATE TABLE [dbo].[dbNicheCIS](
    [OccurrenceID] [decimal](25, 0) NULL,
    [OccurrenceFileNo] [varchar](20) NULL
)

INSERT INTO dbNicheCIS values (90309955000010401948421,'3212')

CREATE TABLE [dbo].[Asset_Table](
    [user_crimenumber] [varchar](4000) NOT NULL
)

INSERT INTO Asset_Table VALUES ('3212; 4512; 34322; 45674; 33221')

我设计的唯一表格是dbNicheCIS。我试图使用Asset_Table语句找到tbx_rrdgeniedeleteditem中的所有行,这些行也位于LIKE中。 Asset_Table包含OccurrenceFileNo(请注意,资产表包含eventsfileno:3212,与OccurrenceID: 90309955000010401948421)相关。我试过这个:

Select user_crimenumber from tbx_rrdgeniedeleteditem --asset_table.user_crimenumber 
inner join dbNicheCIS on tbx_rrdgeniedeleteditem.deletedid = dbNicheCIS.OccurrenceID
cross join asset_table
where deletedid like '903%' and asset_table.user_crimenumber like '%' + occurrencefileno + '%'

它有效,但运行需要数小时。是否有更好的方法来接近它而不是交叉连接?

3 个答案:

答案 0 :(得分:0)

您可以使用INNER JOIN,也可以消除LIKE以进行数字比较,如下所示

Select user_crimenumber from tbx_rrdgeniedeleteditem
inner join dbNicheCIS 
on tbx_rrdgeniedeleteditem.deletedid = dbNicheCIS.OccurrenceID
inner join asset_table
on CAST(LEFT([DeletedId], 3) AS [decimal](25, 0)) =903 
and asset_table.user_crimenumber like '%' + occurrencefileno + '%'

答案 1 :(得分:0)

在这种情况下你可以使用in运算符

SELECT * FROM TBX_RRDGenieDeletedItem
WHERE DeletedId IN (
SELECT DISTINCT OccurrenceID FROM dbNicheCIS
INNER JOIN Split(...) ON ...)

更新:您可以创建自定义拆分功能,将值拆分为临时表,然后执行连接。

答案 2 :(得分:0)

您需要为表编制索引以获得更快的查询响应。

CREATE INDEX [IX_dbNicheCIS_OccurrenceID] ON [dbNicheCIS]
([OccurrenceID] ASC, [OccurrenceFileNo] ASC)

CREATE INDEX [IX_TBX_RRDGenieDeletedItem_DeletedId] ON [dbo].[TBX_RRDGenieDeletedItem]
([DeletedId] ASC)

创建此类索引会替换"表扫描"在查询执行计划中更快"索引扫描"和"指数寻求"。但是你无法用简单的索引来解决like '%' + occurrencefileno + '%'问题。 在那里你必须使用full text indexes。在asset_table.user_crimenumber上定义全文索引后,您可以使用以下查询

SELECT user_crimenumber 
FROM tbx_rrdgeniedeleteditem  di --asset_table.user_crimenumber 
JOIN dbNicheCIS dnc
ON di.deletedid = dnc.OccurrenceID
CROSS JOIN asset_table at
WHERE di.deletedid like '903%' 
AND CONTAINS(at.user_crimenumber, occurrencefileno)

但将occurrencefileno列表存储为以分号分隔的varchar值是一种不好的做法。如果您是此数据库设计的作者,那么您应该尝试对数据进行规范化,这样每个occurrencefileno都会有一行而不是'3212; 4512; 34322; 45674; 33221'这样的字符串。

您还可以在查询asset_table.user_crimenumber的规范化版本之前创建第一步,然后将此表与普通索引一起用作进一步查询的基础。

要按照use the Fn_Split() function分割asset_table.user_crimenumber字段,in this answer


还有一个选项可以使用fnSplit以这种方式重写您的查询:

SELECT user_crimenumber 
FROM tbx_rrdgeniedeleteditem  di --asset_table.user_crimenumber 
JOIN dbNicheCIS dnc
ON di.deletedid = dnc.OccurrenceID
INNER JOIN (
    SELECT at.user_crimenumber, f.item FROM asset_table at 
    CROSS APPLY dbo.fnSplit(at.user_crimenumber,';') f   ) at
ON at.item=dnc.occurrencefileno
WHERE di.deletedid like '903%'

如果您按照here所述在C#中创建fnSplit作为CLR,您可能会获得更快的结果。但它不会神奇地加速您的查询。