如何解决SQL 为什么在添加更多 where 条件时下面的查询很慢
我遇到了一个奇怪的问题,当我添加更多条件时,我的 SQL 查询很慢。
我的表:
CREATE TABLE[dbo].[ASSETS_INFO]
(
[ASSET_ID][int] IDENTITY(1,1) NOT NULL,[OBJECT_ID] [int] NOT NULL,[EQUIPMENT_ID] [nvarchar] (20) NOT NULL,[EQUIPMENT_NAME] [nvarchar] (100) NULL,[USER_NO] [nvarchar] (20) NULL,[PRODUCTER] [int] NULL,[ASSET_TYPE] [nvarchar] (20) NULL,CONSTRAINT[PK_ASSETS_INFO] PRIMARY KEY CLUSTERED
(
[ASSET_ID] ASC
)WITH(PAD_INDEX = OFF,STATISTICS_NORECOMPUTE = OFF,IGNORE_DUP_KEY = OFF,ALLOW_ROW_LOCKS = ON,ALLOW_PAGE_LOCKS = ON) ON[PRIMARY]
) ON[PRIMARY] TEXTIMAGE_ON[PRIMARY]
GO
CREATE TABLE [dbo].[BM_METERINFO](
[METER_ID] [varchar](40) NOT NULL,[CUSTOMER_ID] [varchar](20) NOT NULL,[CUSTOMER_NAME] [varchar](200) NULL,CONSTRAINT [PK_BM_METERINFO] PRIMARY KEY CLUSTERED
(
[METER_ID] ASC,[CUSTOMER_ID] ASC
)WITH (PAD_INDEX = OFF,ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[WSMP_OBJECT](
[OBJECT_ID] [int] IDENTITY(1,[OBJECT_NAME] [nvarchar](50) NOT NULL,[OBJECT_STATE] [int] NOT NULL,[OBJECT_INDEX] [int] NULL,CONSTRAINT [PK_WSMP_OBJECT] PRIMARY KEY CLUSTERED
(
[OBJECT_ID] ASC
)WITH (PAD_INDEX = OFF,ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
我的 SQL 查询 1:
declare @table_count_f1 table
(
OBJECT_ID INT
);
insert into @table_count_f1
select OBJECT_ID from[FNNC_WAPCONFIG_AUTHOR_AREA_WSMPOBJECTIDS] ('2','lams_v2_dev','') order by OBJECT_ID -- get all object_ids which is very quick (more than 60,000 rows)
declare @table_count_f2 table
(
OBJECT_ID INT
);
insert into @table_count_f2
SELECT DISTINCT obj.OBJECT_ID FROM[ASSETS_INFO] A
INNER JOIN[WSMP_OBJECT] OBJ ON OBJ.OBJECT_ID = A.OBJECT_ID
LEFT JOIN dbo.BM_METERINFO bm ON A.USER_NO = BM.CUSTOMER_ID and a.EQUIPMENT_ID = bm.METER_ID
WHERE OBJ.OBJECT_STATE in (0,1,-2) AND(A.SYS_DATA_STATE <> -1 OR A.SYS_DATA_STATE IS NULL)
AND A.ASSET_TYPE in('22')
And case WHEN bm.METER_ID IS null THEN 1 WHEN bm.METER_ID = '' THEN 1 ELSE 2 END = 1
--here is the problem: it got the result when I use either of 'AND',but it runs very slowly when I use both of them.I have added index already
order by OBJECT_ID
select count(*) from @table_count_f1 t1,@table_count_f2 t2
where t1.OBJECT_ID = t2.OBJECT_ID
执行计划
我的 SQL 查询 2:
declare @table_count_f0 table
(
OBJECT_ID INT
);
insert into @table_count_f0
select OBJECT_ID from[FNNC_WAPCONFIG_AUTHOR_AREA_WSMPOBJECTIDS]('2','') order by OBJECT_ID
SELECT A.*,OBJ.OBJECT_INDEX,OBJ.OBJECT_STATE,case WHEN bm.METER_ID IS null THEN 1 WHEN bm.METER_ID = '' THEN 1 ELSE 2 end setState FROM[ASSETS_INFO] A
INNER JOIN[WSMP_OBJECT] OBJ ON OBJ.OBJECT_ID = A.OBJECT_ID
LEFT JOIN dbo.BM_METERINFO bm ON a.EQUIPMENT_ID = bm.METER_ID AND A.USER_NO = BM.CUSTOMER_ID
WHERE OBJ.OBJECT_STATE IN(0,-2) AND(A.SYS_DATA_STATE <> -1 OR A.SYS_DATA_STATE IS NULL)
and OBJ.OBJECT_ID in (select OBJECT_ID from @table_count_f0 )
and case WHEN bm.METER_ID IS null THEN 1 WHEN bm.METER_ID = '' THEN 1 ELSE 2 END = 2
ORDER BY A.EQUIPMENT_NAME asc
OFFSET 20 ROWS
FETCH NEXT 20 ROWS ONLY
问题出在ORDER BY
,当我使用ORDER BY EQUIPMENT_ID
时它很快,但是当我使用ORDER BY EQUIPMENT_NAME
时它很慢,我在ASSETS_INFO
中添加了一个索引SSMS 但它没有效果。
感谢您抽出宝贵时间。
解决方法
我假设您已经有一个关于 WSMP_OBJECT (OBJECT_ID) 的覆盖索引,以及包含覆盖查询的 EQUIPMENT_NAME 的新索引。
您在这里的主要问题是事物的外观排序。您在整个结果集上区分的事实与 SQL Server 不了解您尝试使用左连接做什么的组合意味着它会再次排序,即使它可能已经对数据进行了排序。
本质上,您想要的是针对 WSMP_OBJECT 的半连接和针对 BM_METERINFO 的反连接。
SELECT
obj.OBJECT_ID
FROM [ASSETS_INFO] A
INNER JOIN [WSMP_OBJECT] OBJ ON OBJ.OBJECT_ID = A.OBJECT_ID
WHERE OBJ.OBJECT_STATE in (0,1,-2)
AND (A.SYS_DATA_STATE <> -1 OR A.SYS_DATA_STATE IS NULL)
AND A.ASSET_TYPE in('22')
AND NOT EXISTS (SELECT 1
FROM dbo.BM_METERINFO bm
WHERE A.USER_NO = BM.CUSTOMER_ID and a.EQUIPMENT_ID = bm.METER_ID
AND bm.METER_ID <> '')
order by OBJECT_ID
同样(这里我相信 setState 永远是 2):
SELECT
A.*,OBJ.OBJECT_INDEX,OBJ.OBJECT_STATE,2 setState
FROM [ASSETS_INFO] A
INNER JOIN [WSMP_OBJECT] OBJ ON OBJ.OBJECT_ID = A.OBJECT_ID
WHERE OBJ.OBJECT_STATE IN(0,-2) AND(A.SYS_DATA_STATE <> -1 OR A.SYS_DATA_STATE IS NULL)
and OBJ.OBJECT_ID in (select OBJECT_ID from @table_count_f0 )
AND NOT EXISTS (SELECT 1
FROM dbo.BM_METERINFO bm
WHERE A.USER_NO = BM.CUSTOMER_ID and a.EQUIPMENT_ID = bm.METER_ID
AND bm.METER_ID <> '')
ORDER BY A.EQUIPMENT_NAME asc
OFFSET 20 ROWS
FETCH NEXT 20 ROWS ONLY
,
我不知道为什么下面的代码更快,它似乎仍然与索引有关。
修改后的 SQL 查询 1:
declare @table_count_f1 table
(
OBJECT_ID INT
);
insert into @table_count_f1
select OBJECT_ID from [FNNC_WAPCONFIG_AUTHOR_AREA_WSMPOBJECTIDS] ('2','lams_v2_dev','') order by OBJECT_ID
declare @table_count_f2 table
(
OBJECT_ID INT,PRODUCTER INT,ASSET_TYPE INT
);
insert into @table_count_f2
SELECT DISTINCT obj.OBJECT_ID,A.PRODUCTER,A.ASSET_TYPE FROM [ASSETS_INFO] A
INNER JOIN[WSMP_OBJECT] OBJ ON OBJ.OBJECT_ID = A.OBJECT_ID
LEFT JOIN dbo.BM_METERINFO bm ON A.USER_NO = BM.CUSTOMER_ID and a.EQUIPMENT_ID = bm.METER_ID
WHERE OBJ.OBJECT_STATE in (0,-2) AND(A.SYS_DATA_STATE <> -1 OR A.SYS_DATA_STATE IS NULL)
--AND A.ASSET_TYPE in('22')
-- AND A.PRODUCTER in ('1')
and case WHEN bm.METER_ID IS null THEN 1 WHEN bm.METER_ID='' THEN 1 ELSE 2 END=1
AND OBJ.OBJECT_STATE in(1)
order by OBJECT_ID
select count(*) from @table_count_f1 t1,@table_count_f2 t2
where t1.OBJECT_ID=t2.OBJECT_ID
AND t2.PRODUCTER in ('1')
AND t2.ASSET_TYPE in ('22')
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。