2016-06-30 17 views
0

Ich habe eine Reihe von TabellenSQL Server 2014 Tabelle/Abfrage-Optimierung

dbo.Store_000 
dbo.Store_001 
.... 
dbo.Store_216 

den Verkauf von verschiedenen Geschäften enthalten, wobei relevante Felder sind

Username, ItemID, Description, CreatedDate, CountryID 

ich die letzten 20 Verkäufe extrahieren müssen aus alle Geschäfte und ich schrieb die folgende Abfrage:

select top 20 UserName, ItemID, Description, CreatedDate, CountryID 
FROM ( 
    SELECT UserName, ItemID, Description, CreatedDate, CountryID FROM dbo.Store_000 
    UNION ALL 
    SELECT UserName, ItemID, Description, CreatedDate, CountryID FROM dbo.Store_001 
    UNION ALL 
    SELECT UserName, ItemID, Description, CreatedDate, CountryID FROM dbo.Store_002 
    ..... 
    ... 
    UNION ALL 
    SELECT UserName, ItemID, Description, CreatedDate, CountryID FROM dbo.Store_216     
) ii 
order by ii.createdDate desc 

derzeit Tabellen enthält einige 200M Datensätze (alle togethe r)

deshalb die Verarbeitungszeit zu reduzieren Ich habe den folgenden Index für jede Tabelle:

CREATE NONCLUSTERED INDEX I2_Store000 ON dbo.Store_000 
    (UserName) 
INCLUDE (itemId, Description, CreatedDate, CountryID) 
WITH (
    PAD_INDEX = OFF, 
    DROP_EXISTING = OFF, 
    STATISTICS_NORECOMPUTE = OFF, 
    SORT_IN_TEMPDB = OFF, 
    ONLINE = OFF, 
    ALLOW_ROW_LOCKS = ON, 
    ALLOW_PAGE_LOCKS = ON) 
ON [PRIMARY] 

aber es dauert immer noch zu viel (einige Minuten auf unserer Maschine)

können Sie vorschlagen, wie zur Verbesserung des die Abfrage und oder der Index, um die Verarbeitungszeit zu reduzieren?

sollte ich den Index basierend auf CreatedDate erstellen, da das das Sortierfeld ist?

Wenn es helfen kann, kann HERE den MSSMS-Ausführungsplan finden.

dank

+0

Eralper korrekt ist. Außerdem ignorieren Sie die Datensatztheorie, indem Sie Datensätze als Cursor behandeln und im Wesentlichen 21 verschiedene Abfragen ausführen. Das Internet ist voll von produktiven Tutorials zum Erstellen von Abfragen, wie zum Beispiel gedankenbot.com, blog.SQLAuthority und TECHNET. Für eine schnelle Auffrischung der Abfrage, lesen Sie [Thoughtbot-Seite] (https://robots.thoughtbot.com/back-to-basics-sql). –

+0

Hallo, was meinst du mit 'Data Set Theory 'durch Behandeln von Datensätzen als Cursor und im Wesentlichen 21 verschiedene Abfragen laufen? Wo kann ich etwas finden? – Joe

+0

Eine Art, Datenbanksprachen zu sagen, sind keine zeilenweisen Sprachen wie C++ und Behandlungstabellen (Datensätze) als Ganzes. Auschecken SQLMag [T-SQL-Grundlagen: Denken in Sets] (http://sqlmag.com/t-sql/t-sql-foundations-thinking-sets) –

Antwort

2

Just for Leistung soll ich nur aus jeder Tabelle durch CreatedDate geordneten obere 20 Zeilen auszuwählen, und dann eine neue Top 20 aus der neuen abgeleiteten Tabelle auszuwählen, die etwa 17 Tabelle * 20 = 340 Zeilen

ist

Ich hoffe, es wird einfacher sein, mit kleineren Tisch umzugehen, ich frage mich wirklich das Ergebnis.

+0

Hallo, danke für prompte Antwort ... eigentlich hat sich die Situation verbessert, aber nicht genug: jetzt dauert es 4 Minuten, aber das Entfernen der inneren Sortierung dauert ungefähr 1 Sekunde, daher denke ich, dass ich einen Index basierend auf createdDate erstellen muss, aber da ich einen anderen Index habe, muss ich verstehen, ob es besser (und möglich) ist, diesen Index zu erweitern oder einen zweiten Index zu erstellen. – Joe

+0

@Joe Wofür ist dieser Index? Das einzige "Prädikat", das Sie haben, ist nach "createdDate" und "TOP" zu sortieren. Wie könnte der Index für 'UserName' hier hilfreich sein? –

+0

Nun, das ist eigentlich ein Index, den ich bereits auf dieser Tabelle habe, da ich diese Tabelle mit anderen auf Benutzername verbinden muss, und ich 'CreatedDate' im Include hinzufügen, aber nicht so viel hilft, auf der anderen Seite würde ich gerne Erstellen Sie einen weiteren Index für 200M-Datensätze – Joe

0

Die erste (und schnellere) Option wäre, führen Sie eine TOP 20 auf Ihre Unterabfragen, bevor Sie dann in der äußeren Auswahl, etwas in der Art sortieren;

select top 20 UserName, ItemID, Description, CreatedDate, CountryID 
FROM ( 
    SELECT TOP 20 UserName, ItemID, Description, CreatedDate, CountryID FROM dbo.Store_000 ORDER BY CreatedDate DESC 
    UNION ALL 
    SELECT TOP 20 UserName, ItemID, Description, CreatedDate, CountryID FROM dbo.Store_001 ORDER BY CreatedDate DESC 
    UNION ALL 
    SELECT TOP 20 UserName, ItemID, Description, CreatedDate, CountryID FROM dbo.Store_002ORDER BY CreatedDate DESC 
    ..... 
    ... 
    UNION ALL 
    SELECT TOP 20 UserName, ItemID, Description, CreatedDate, CountryID FROM dbo.Store_216 ORDER BY CreatedDate DESC     
) ii 
order by ii.createdDate desc 

Der Index, den Sie auf jeder Tabelle wollen, wird so sein (Indexname nur ein Beispiel);

CREATE NONCLUSTERED INDEX [IX_Store_000_CreatedDate_Desc_Incl] ON [dbo].[Store_000] ([CreatedDate] DESC) 
INCLUDE ([UserName],[ItemID],[Description],[CreatedDate],[CountryID]) 

Ihre andere Option besteht darin, eine indizierte Sicht zu erstellen, wenn Sie diese regelmäßig aufrufen. Es gibt Vor- und Nachteile einer indizierten Sichtweise, so dass Sie diesen Aufruf selbst durchführen müssen, siehe unten.

https://www.simple-talk.com/sql/learn-sql-server/sql-server-indexed-views-the-basics/

https://www.brentozar.com/archive/2013/11/what-you-can-and-cant-do-with-indexed-views/

SQL Server - Creating an Indexed View

0

Es gibt noch andere Techniken, die Sie, dass die Abfrage optimieren könnte nutzen könnten. Jetzt ist UNION ALL geeignet, da die Werte aus jeder Tabelle eindeutig sein sollten.

Alex Martelli von What is the difference between JOIN and UNION?

UNION Linien von Anfragen nach einander legt, macht JOIN, während ein kartesisches Produkt und Subsets es - völlig unterschiedliche Vorgänge.Trivial Beispiel UNION:

mysql> SELECT 23 AS bah 
    -> UNION 
    -> SELECT 45 AS bah; 
+-----+ 
| bah | 
+-----+ 
| 23 | 
| 45 | 
+-----+ 2 rows in set (0.00 sec) similary trivial example of JOIN: 

mysql> SELECT * FROM 
    -> (SELECT 23 AS bah) AS foo 
    -> JOIN 
    -> (SELECT 45 AS bah) AS bar 
    -> ON (33=33); 
+-----+-----+ 
| bah | bah | 
+-----+-----+ 
| 23 | 45 | 
+-----+-----+ 1 row in set (0.01 sec) 
  • USE A PREDICATE IN ALL 20+ Tabellen.

UNION ALL kann wirksam sein, aber es hat immer noch die gesamte Tabelle zu sortieren, sondern die TOP 20 zu identifizieren, die Geschäfte immer mehr als 20 Verkäufe in einem bestimmten Zeitraum von 30 Tagen unter der Annahme haben, verwenden Sie DATEADD oder DATEDIFF Aktivieren Sie boolean Vergleiche, die die Anzahl der Zeilen begrenzen SQL Server muss mit vor dem Vergleich zurückgegeben werden.

  • einen Index verwenden ... in der rechten Spalte

Offensichtlich Ihr Bericht sollte INDEXES und logische noch dazu verwenden. CLUSTERED INDEXES sind weniger teuer zu bauen und zu warten.

Sie wissen, Namen könnten einzigartig sein, aber SQL Server vergleicht keine Namen ... es ist ein Vergleich der DATEN. Erstellen Sie daher einen INDEX auf createdDate.

  • USE Suchargumente (SARG)

Selbst die besten Pläne ruiniert werden kann, wenn SQL Server denkt, dass es durch jeden Datensatz jedes Mal gehen müssen. Wenn ein FUNCTION oder variabel auf beiden Seiten des Prädikats verwendet werden, wie unten:

createdDATE BETWEEN DATEADD(DD, createdDate, 30) AND CAST(GETDATE() AS DATETIME2)

SQL Server hat keine andere Wahl, als die gesamte Tabelle oder Index-Liste zu durchlaufen (TABLE/INDEX SCAN), bevor Werte zu vergleichen. Stattdessen ordnen es wie folgt aus:

createdDATE >= DATEADD(DD, -30, GETDATE())

Vergleichen Sie die Ergebnisse mit dieser Abfrage und wie ein Index für CreatedDate verbessert die Zeit:

SELECT UserName, ItemID, Description, CreatedDate, CountryID 
FROM ( 
    SELECT TOP 20 UserName, ItemID, [Description], CreatedDate, CountryID FROM dbo.Store_000 
    WHERE CreatedDate >= DATEADD(DD, -30, GETDATE()) 
    UNION ALL 
    SELECT TOP 20 UserName, ItemID, [Description], CreatedDate, CountryID FROM dbo.Store_001 
    WHERE CreatedDate >= DATEADD(DD, -30, GETDATE()) 
    UNION ALL 
    SELECT TOP 20 UserName, ItemID, [Description], CreatedDate, CountryID FROM dbo.Store_002 
    WHERE CreatedDate >= DATEADD(DD, -30, GETDATE()) 
    ..... 
    ... 
    UNION ALL 
    SELECT TOP 20 UserName, ItemID, [Description], CreatedDate, CountryID FROM dbo.Store_216 
    WHERE CreatedDate >= DATEADD(DD, -30, GETDATE()) 
) ii 
-- ORDER BY CreatedDate DESC /*Unless you must, drop the ORDER BY. */ 
+0

All dies ist ein Beispiel für die Verwendung relationaler Daten. :) –

Verwandte Themen