2017-02-28 2 views
0

Ich habe zwei Tabellen wie unten in einer anderen Tabelle existiert:effizienteste Weg, Datensätze aus einer Tabelle zu erhalten, für die ein Datensatz für jeden Monat

User: User_ID, User_name and some other columns (has approx 1000 rows) 
Fee: Created_By_User_ID, Created_Date and many other columns (has 17 million records) 

Gebühren-Tabelle hat keinen Index (und ich kann nicht erstelle einen).

Ich brauche eine Liste von Benutzern für jeden Monat eines Jahres (sagen 2016), die mindestens eine Gebühr erstellt haben.

Ich habe eine Arbeitsabfrage, die lange dauert, um auszuführen. Kann mir jemand bei einer besseren Abfrage helfen? Kann EXIST Klausel verwenden (habe ich versucht, eine, sondern nimmt immer noch Zeit, wie es Fee Tabelle scannt)

SELECT MONTH(f.Created_Date), f.Created_By_User_ID 
FROM Fees f 
JOIN [User] u ON f.Created_By_User_ID= u.User_ID 
WHERE f.Created_Date BETWEEN '2016-01-01' AND '2016-12-31' 
+0

hinzufügen 'wählen DISTINCT'. Wenn Sie eine Benutzerliste benötigen, müssen Sie nicht das gesamte Los auswählen. – cha

Antwort

1

Sie einen Scan der Gebührentabelle einmal in der ursprünglichen Abfrage benötigen Sie verwenden. Wenn Sie nur den Join direkt verwenden, wie in der ursprünglichen Abfrage, benötigen Sie mehrere Scans der Gebührentabelle, von denen viele redundante Zeilen durchlaufen, während der Join auftritt. Das gleiche Szenario tritt auf, wenn Sie eine von Mansoor vorgeschlagene innere Abfrage verwenden.

Eine Optimierung könnte darin bestehen, die Anzahl der Zeilen zu verringern, auf denen die Joins stattfinden. Unter der Annahme, dass die Benutzertabelle nur einen Datensatz pro Benutzer enthält und die Gebührentabelle mehrere Datensätze pro Person aufweist, können wir versuchen, mithilfe eines CTE verschiedene Monate zu finden, für die Benutzer einen Kauf getätigt haben. Dann können wir einen Join über diesem CTE machen, dies wird die durch den Join durchgeführte Berechnung reduzieren und sollte eine etwas bessere Ausgabezeit ergeben, wenn über einen großen Datensatz gearbeitet wird.

Versuchen Sie folgendes:

WITH CTE_UserMonthwiseFeeRecords AS 
(
SELECT DISTINCT Created_By_User_ID, MONTH(Created_Date) AS FeeMonth 
FROM Fee 
WHERE Created_Date BETWEEN '2016-01-01' AND '2016-12-31' 
) 
SELECT User_name, FeeMonth 
FROM CTE_UserMonthwiseFeeRecords f 
INNER JOIN [User] u ON f.Created_By_User_ID= u.User_ID 

Außerdem haben Sie nicht erwähnt, dass Sie die Benutzernamen und alle erfordern, wenn auch nur id zum Zwecke der Suche verschiedene Benutzer erforderlich ist, Einkäufe pro Monat machen, dann können Sie einfach verwenden, um die Abfrage innerhalb des CTE und nicht einmal erforderlich, die JOIN wie:

SELECT DISTINCT Created_By_User_ID, MONTH(Created_Date) AS FeeMonth 
FROM Fee 
WHERE Created_Date BETWEEN '2016-01-01' AND '2016-12-31' 
+0

Danke @ DK5. Diese Abfrage wird relativ schneller ausgeführt. –

+0

Gern geschehen :) – DK5

0
Try below query : 

SELECT MONTH(f.Created_Date), f.Created_By_User_ID 
FROM Fees f 
WHERE EXISTS(SELECT 1 FROM [User] u WHERE f.Created_By_User_ID= u.User_ID 
AND DATEDIFF(DAY,f.Created_Date,'2016-01-01') <= 0 AND 
    DATEDIFF(DAY,f.Created_Date,'2016-12-31') >= 0 
+0

Vielen Dank für eine schnelle Antwort. Aber diese Abfrage braucht auch Zeit. Der Ausführungsplan zeigt, dass dies eine wenig günstigere Abfrage ist. –

+0

Diese Abfrage benötigt aufgrund der inneren Abfrage, die eine Variable aus der äußeren Abfrage verwendet, mehr Zeit. Dies wird nicht empfohlen und sollte die Leistung weiter verlangsamen als die ursprüngliche Abfrage. – DK5

0

Sie versuchen, diesen Ansatz kann die Abfrage der Laufzeit zu reduzieren. Es kopiert jedoch die riesigen Daten und speichert eine Instanz der Tabelle (Temp_Fees). Bei jeder DML, die für die Tabelle Gebühren/Benutzer ausgeführt wird, muss die Tabelle Temp_Fees gekürzt und neu geladen werden.

Select * into Temp_Fees from (SELECT MONTH(f.Created_Date) as Created_MONTH, f.Created_By_User_ID 
FROM Fees f 
WHERE f.Created_Date BETWEEN '2016-01-01' AND '2016-12-31') 


SELECT f.Created_MONTH, f.Created_By_User_ID 
FROM Temp_Fees f 
JOIN [User] u ON f.Created_By_User_ID= u.User_ID 
Verwandte Themen