有效地基于“过滤器”表从一个表中获取结果

问题描述 投票:2回答:4

我有2个表,表A包含销售数据,而表B包含表A中的某些列,这些列将需要用作过滤器以从表A中获得匹配的结果。我可以获取所需的结果,但是需要一个时间长了,我怀疑我的做法不是很有效。此逻辑在多个数据库中使用,因此有时表A和B很小,仅需一秒钟,而其他数据库则大得多,每个表中的记录都在10到10的几千个中。

这是两个表的演示脚本,生产中的列比此更多,但这可以说明问题:

Create Table A
(
    ID int Identity(1,1),
    City nvarchar(255),
    State nvarchar(255),
    Zip nvarchar(255),
    Territory nvarchar(255)
)

Insert Into A Values 
('Chicago', 'IL', 'Zip1', 'Territory1'),
('Houston', 'TX', 'Zip2', 'Territory2'),
('Atlanta', 'AL', 'Zip3', 'Territory3'),
('Denver', 'CO', 'Zip4', 'Territory4'),
('Detroit', 'MI', 'Zip5', 'Territory1'),
('Seattle', 'WA', 'Zip6', 'Territory5'),
('Springfield', 'IL', 'Zip7', 'Territory1'),
('Springfield', 'MO', 'Zip8', 'Territory1'),
('Tacoma', 'WA', 'Zip10', 'Territory5'),
('Portland', 'OR', 'Zip10', 'Territory5' )


Create Table B
(
    ID int Identity(1,1),
    City nvarchar(255),
    State nvarchar(255),
    Zip nvarchar(255),
    Territory nvarchar(255)
)

Insert Into B Values
('Chicago', NULL, NULL, NULL),
('Springfield', 'IL', NULL, 'Territory1'),
(NULL, NULL, 'Zip2', NULL),
(NULL, 'WA', NULL, 'Territory5')

我需要获得所需记录的东西看起来像这样:

Select * 
from A inner join B
on A.City like Coalesce(B.City, A.City)
and A.State like Coalesce(B.State, A.State)
and A.Zip like Coalesce(B.Zip, A.Zip)
and A.Territory like Coalesce(B.Territory, A.Territory)
--More joins in production for remaining columns

这可以工作,但是由于有大量的记录和其他联接,因此对于某些数据库来说,这需要一些时间。有什么方法可以加快速度,或者可以更有效地处理我所看不到的吗?

sql sql-server
4个回答
2
投票

首先,强烈建议您避免对字符串使用like,除非您别无选择,除了您的公司,我认为通过以下类似的更改,您的查询会更快:

Select * 
from A inner join B
on (A.City =B.City OR B.City IS NULL)
and (A.State =B.State OR B.State IS NULL)
and (A.Zip =B.Zip OR B.Zip IS NULL)
and (A.Territory =B.Territory OR B.Territory IS NULL)

1
投票

[包括条件的精确匹配可能是更好的选择,只要这四列(A.CityA.StateA.ZipA.Territory)中至少有一个具有索引:

SELECT * 
  FROM A 
  JOIN B
    ON CASE WHEN B.City is null THEN A.City ELSE B.City END = A.City
   AND CASE WHEN B.State is null THEN A.State else B.State END = A.State 
   AND CASE WHEN B.Zip is null THEN A.Zip ELSE B.Zip END = A.Zip
   AND CASE WHEN B.Territory is null THEN A.Territory ELSE B.Territory END = A.Territory

0
投票

我在您的CASE选项的where子句中想到了ISNULL选项,但听起来像您有选项。

Select * 
from A inner join B
on (A.City = isnull(B.City, A.City))
and (A.State = isnull(B.State, A.State))
and (A.Zip = isnull(B.Zip, A.Zip))
and (A.Territory = isnull(B.Territory, A.Territory))

0
投票

除了精确匹配之外,在用于联接表的列上创建索引也会加快查询速度。

© www.soinside.com 2019 - 2024. All rights reserved.