J'ai la requête suivante qui prend environ 4 minutes à exécuter.
SELECT c.id AS clid,
h.id AS hlid,
h.holdinNo,
c.cliendID,
c.clientName,
h.floor,
h.connect_radius
FROM [db_land].[dbo].tbl_client AS c
INNER JOIN [db_land].[dbo].tx_holding AS h
ON c.id = h.clid
WHERE h.status = 1
AND h.connect_radius IS NOT NULL
AND c.status = 1
AND h.type = 'Residential'
J'ai trouvé que la jointure interne ne prend que quelques secondes.
DECLARE @tdate DATETIME = '2019-09-01 00:00:00.000'
SELECT c.id AS clid,
h.id AS hlid,
h.holdinNo,
c.cliendID,
c.clientName,
h.floor,
h.connect_radius
FROM [db_land].[dbo].tbl_client AS c
INNER JOIN [db_land].[dbo].tx_holding AS h
ON c.id = h.clid
WHERE h.status = 1
AND h.connect_radius IS NOT NULL
AND c.status = 1
AND h.type = 'Residential'
AND h.holdinNo NOT IN (SELECT holdingNo
FROM [db_land].[dbo].tbl_bill
WHERE year(date_month) = YEAR(@tdate)
AND MONTH(date_month) = MONTH(@tdate)
AND ( update_by IS NOT NULL
OR ispay = 1 ))
C'est la vérification NOT IN qui prend beaucoup de temps. Comment puis-je optimiser cette requête? Pour moi, il est nécessaire d'exécuter la requête au moins en une minute.
7 Réponses :
Essayez de remplacer NOT IN par un LEFT JOIN de la table [db_land]. [dbo] .tbl_bill sur toutes les conditions et ajout de la clause WHERE holdingNo est nul afin que les lignes renvoyées soient les lignes non correspondantes:
select c.id as clid, h.id as hlid,h.holdinNo, c.cliendID, c.clientName, h.floor, h.connect_radius from [db_land].[dbo].tbl_client as c inner join [db_land].[dbo].tx_holding as h on c.id= h.clid left join [db_land].[dbo].tbl_bill as b on b.holdingNo = h.holdinNo and year(b.date_month) = YEAR(@tdate) and MONTH(b.date_month) = MONTH(@tdate) and (b.update_by is not null or b.ispay = 1) where h.status = 1 and h.connect_radius is not null and c.status=1 and h.type='Residential' and b.holdingNo is null
mettre la liste de filtres à variable, puis les appliquer le filtre
DECLARE @tdate DATETIME = '2019-09-01 00:00:00.000'
SELECT c.id AS clid,
h.id AS hlid,
h.holdinNo,
c.cliendID,
c.clientName,
h.floor,
h.connect_radius
FROM [db_land].[dbo].tbl_client AS c
INNER JOIN [db_land].[dbo].tx_holding AS h ON c.id= h.clid
WHERE h.status=1
AND h.connect_radius IS NOT NULL
AND c.status=1
AND h.type='Residential'
AND h.holdinNo NOT IN (filter)
eux appliquer le filtre
DECLARE @filter TABLE INSERT INTO @filter SELECT FROM [db_land].[dbo].tbl_bill
Assurez-vous que les prédicats des clauses WHERE et JOIN sont sargables. L'application d'une fonction à une colonne (par exemple YEAR (date_month) ) empêche l'utilisation efficace des index de la colonne.
Essayez plutôt cette expression pour éviter les fonctions. Il existe d'autres méthodes selon la version de SQL Server.
WHERE
date_month >= DATEADD(day, 1, DATEADD(month, -1, EOMONTH(@tdate)))
AND date_month < DATEADD(day, 1, DATEADD(month, 1, EOMONTH(@tdate)))
DATEADD () et EOMONTH () ne sont pas des fonctions? !!! Votre code n'est pas conforme à vos affirmations.
Ce sont des fonctions mais elles ne sont pas appliquées à une colonne. Ils sont appliqués sur des variables
@MartinSmith, sauf si je manque quelque chose, date_month semble être un nom de colonne. Les fonctions sont également appliquées aux variables de la requête.
ma réponse a été à @forpas. Répondre à DATEADD () et EOMONTH () ne sont pas des fonctions? !!!
Je recommanderais de changer le NOT IN en NOT EXISTS et d'ajouter un index:
WHERE . . . AND
NOT EXISTS (SELECT 1
FROM [db_land].[dbo].tbl_bill b
WHERE b.holdingNo = h.holdingNo AND
b.date_month >= DATEFROMPARTS(YEAR(@tdate), MONTH(@tdate), 1) AND
b.date_month < DATEADD(month, 1, DATEFROMPARTS(YEAR(@tdate), MONTH(@tdate), 1)) AND
(b.update_by IS NOT NULL OR b.ispay = 1
)
Ensuite, l'index que vous voulez est le tbl_bill (holdingNo, date_month, update_by, ispay) .
Placez votre sous-requête dans la table temporaire:
DECLARE @tdate DATETIME = '2019-09-01 00:00:00.000'
SELECT holdingNo
into #TmpholdingNo
FROM [db_land].[dbo].tbl_bill
WHERE year(date_month) = YEAR(@tdate)
AND MONTH(date_month) = MONTH(@tdate)
AND ( update_by IS NOT NULL
OR ispay = 1 )
SELECT c.id AS clid,
h.id AS hlid,
h.holdinNo,
c.cliendID,
c.clientName,
h.floor,
h.connect_radius
FROM [db_land].[dbo].tbl_client AS c
INNER JOIN [db_land].[dbo].tx_holding AS h
ON c.id = h.clid
WHERE h.status = 1
AND h.connect_radius IS NOT NULL
AND c.status = 1
AND h.type = 'Residential'
AND h.holdinNo NOT IN (SELECT holdingNo from #TmpholdingNo)
drop table #TmpholdingNo
Plutôt que d'utiliser des fonctions dans votre clause WHERE , essayez de calculer les dates de début et de fin du filtre, l'utilisation de OPTION (RECOMPILE) peut aider SQL à utiliser les valeurs réelles de vos variables dans votre plan de requête. Je changerais également NOT IN en NOT EXISTS :
DECLARE @tdate DATETIME = '2019-09-01 00:00:00.000'
DECLARE @startDate DATE = DATEFROMPARTS(YEAR(@tdate), MONTH(@tdate), 1)
DECLARE @endDate DATE = DATEADD(day,1,EOMONTH(@tdate))
SELECT c.id AS clid,
h.id AS hlid,
h.holdinNo,
c.cliendID,
c.clientName,
h.floor,
h.connect_radius
FROM [db_land].[dbo].tbl_client AS c
INNER JOIN [db_land].[dbo].tx_holding AS h
ON c.id = h.clid
WHERE h.status = 1
AND h.connect_radius IS NOT NULL
AND c.status = 1
AND h.type = 'Residential'
AND NOT EXISTS (SELECT holdingNo
FROM [db_land].[dbo].tbl_bill
WHERE holdingNo = h.holdinNo AND
date_month >= @startDate AND
date_month < @endDate AND
AND ( update_by IS NOT NULL
OR ispay = 1 ))
OPTION (RECOMPILE)
essayer, essayez ceci:
select main.* from
(SELECT c.id AS clid,
h.id AS hlid,
h.holdinNo,
c.cliendID,
c.clientName,
h.floor,
h.connect_radius
FROM [db_land].[dbo].tbl_client AS c
INNER JOIN [db_land].[dbo].tx_holding AS h
ON c.id = h.clid
WHERE h.status = 1
AND h.connect_radius IS NOT NULL
AND c.status = 1
AND h.type = 'Residential')main
left join
(select holdingNo from
(SELECT holdingNo, update_by, ispay
FROM [db_land].[dbo].tbl_bill
WHERE year(date_month) = YEAR(@tdate)
AND MONTH(date_month) = MONTH(@tdate))bill1
where update_by IS NOT NULL OR ispay = 1)bill2
on main.holdinNo = bill2.holdinNo
where bill2.holdinNo is null
Vous avez trois hypothèses différentes quant à la nature du problème. Téléchargez le XML pour le plan d'exécution réel afin que nous puissions voir précisément où se situe le problème