2017-08-24 7 views
2

J'ai une table avec toutes nos commandes. Les commandes sont liées à une personne. Et chaque personne est attachée à une entreprise. Maintenant, j'ai besoin d'une liste de toutes les entreprises qui n'ont jamais commandé avant une certaine date. La requête fonctionne bien, mais c'est très lent.Meilleure requête tsql pour savoir qui est un nouveau client (ou une alternative à NOT EXISTS)

C'est ma requête T-SQL:

SELECT 
    DISTINCT p1.company_id 
FROM 
    order o 
    JOIN person p1 ON (o.person_id = p1.id AND p1.company_id IS NOT NULL) 
WHERE 
    o.orderDate > '2017-01-01' 
AND 
    o.orderDate < '2017-09-01' 
AND NOT EXISTS (SELECT 
        p2.company_id 
       FROM 
        order o2 
        JOIN person p2 ON (o2.person_id = p2.id AND p2.company_id = p1.company_id) 
       WHERE 
        o2.orderDate < '2017-01-01') 

Je l'ai déjà changé d'un PAS à PAS EXISTE. Puisque c'était ce que la plupart des gens ici recommandé. N'a pas aidé beaucoup. Un meilleur index a amélioré un peu la situation, mais la requête est toujours lente. Je suppose que c'est parce que pour chaque commande, il doit faire la sous-requête.

C'est le plan d'exécution: https://www.brentozar.com/pastetheplan/?id=SyAlAU3db
Pour des raisons de simplicité j'ai enlevé quelques clauses WHERE dans mon exemple ci-dessus)

La requête est exécutée sur SQL Azure (et SQL Server Express 12 pour le développement)

Quelqu'un a une meilleure idée sur la façon de résoudre ce problème?

+2

questions visant à obtenir l'aide de la performance devraient inclure DDL, DML des tables impliquées avec test de data..if vos données de test est grande, essayez les scripts sur le schéma et les statistiques pour la table ('right click database-> générer des scripts-> sélectionnez des objets de base de données spécifiques-> dans l'écran suivant sélectionnez avancé et choisissez Script statistics)' et collez-le en question..Avec cette info quelqu'un vous reproche le même problème sont confrontés.Autrement, il devient très difficile de répondre à votre question. Version du serveur de présentation aide également – TheGameiswar

+1

Pourriez-vous nous montrer le plan d'exécution actuel son e: https://www.brentozar.com/pastetheplan/ –

+0

@Rammy Un coup plus simple pour vous. Avez-vous essayé EXCEPT déclaration? Il y a deux sous-ensembles similaires, c'est parti. De plus, si la note précédente n'a pas de sens, analysez un plan d'exécution pour 1) indexer 2) les types de colonnes. – hastrb

Répondre

1

Si vous avez un plan d'exécution pour partager, il vous aidera à analyser les performances.

J'ai fait quelques changements sur la requête comme ci-dessous, vous pouvez essayer si cela l'améliorer

SELECT p1.company_id 
FROM order o 
INNER JOIN person p1 
    ON (o.person_id = p1.id AND p1.company_id IS NOT NULL) 
GROUP BY p1.company_id 
HAVING SUM(CASE WHEN (o.orderDate > '2017-01-01' AND o.orderDate < '2017-09-01') THEN 1 ELSE 0 END) > 0 
     AND 
     SUM(CASE WHEN orderDate < '2017-01-01' THEN 1 ELSE 0 END) = 0 
+0

Sub seconde exécution (par rapport à 12s). Génie! Merci beaucoup. – Remy

0

Je pense que ce serait le faire (oups l'ont pas manqué commandé)

;With FirstOrders 
as 
(
    Select p1.company_id 
    ,  MIN(o.orderDate) as FirstCompanyOrder 
    From Orders o 
    Join Person P1 on o.person_id = p1.id 
    Group by P1.Company_id 
    Having MIN(o.OrderDate) < '2017-01-01' 
) 

Select distinct o.company_id 
From  Orders  o 
Left join FirstOrders FO on o.Company_id = FO.ComapnyId 
where FO.company_id is null 
1

Qu'est-ce à propos de celui-ci. J'espère avoir compris la tâche correctement.

(
    SELECT p1.company_id 
    FROM order o 
    JOIN person p1 
    ON o.person_id = p1.id 
    WHERE p1.company_id IS NOT NULL 
    AND o.orderDate > '2017-01-01' 
    AND o.orderDate < '2017-09-01' 
) 
EXCEPT 
(
    SELECT p2.company_id 
    FROM order o2 
    JOIN person p2 
    ON o2.person_id = p2.id 
    WHERE p2.company_id IS NOT NULL 
    AND o2.orderDate < '2017-01-01' 
) 
+0

Juste besoin d'être distinct. – cloudsafe

+0

@cloudsafe Il ne nécessite pas de DISTINCT redondant. Ce sera un ensemble unique sans doublons. – hastrb

+0

Peut-être que je suis un malentendu, mais que se passe-t-il s'il y a beaucoup de commandes pour la même personne? – cloudsafe

0

Peut être cela vous aidera à:

WITH cte AS 
(
    SELECT o.person_id, MIN(o.orderDate) minOrderDate 
     FROM order o 
     GROUP BY o.person_id 
) 
SELECT DISTINCT p1.company_id 
    FROM person p1 
    JOIN cte ON cte.person_id = p1.id 
    WHERE p1.company_id IS NOT NULL AND cte.minOrderDate > '2017-01-01' AND cte.minOrderDate < '2017-09-01';