Ich habe ein interessantes für alle SQL-Guru da draußen. Jetzt dauert diese Suche nur ein paar Sekunden, ist aber ziemlich intensiv und es muss einen besseren Weg geben. Vielleicht erwarte ich zu viel?
Einfache Urlaubssuch-App. 2 Millionen Ferien. Paging / Sortieren von ca. 600.000 Zeilen.
Dies ist das Schema der Tabelle
CREATE TABLE [dbo].[Holiday](
[Id] [int] NOT NULL,
[PropertyId] [int] NOT NULL,
[Price] [int] NOT NULL,
[Rating] [int] NOT NULL,
[Country] [char](2) NOT NULL,
[ResortId] [int] NOT NULL,
[DepartureAirport] [char](3) NOT NULL,
[DestinationAirport] [char](3) NOT NULL,
[DepartureDate] [datetime] NOT NULL,
[Basis] [char](2) NOT NULL,
[Duration] [int] NOT NULL,
CONSTRAINT [PK_Holiday] PRIMARY KEY CLUSTERED ([Id] ASC)
)
Wie Sie sehen können, ganz einfach. Wir haben eine Immobilie, einen Preis, eine Dauer, Abflug- / Zielflughäfen usw. Je mehr Felder zur Verfügung gestellt werden, desto schneller ist die Suche. Wenn ich einen Abflughafen, eine Immobilie und ein Datum habe, ist die Suche sehr schnell. Wenn ich jedoch nur ein Land und nichts anderes habe, müssen viele Daten verarbeitet werden.
Mit diesem CSV-Export meiner Tabelle gibt es insgesamt 2 Millionen Zeilen und ungefähr 666.000, nur mit dem Ländercode FR, was mein Beispiel ist.
Dies ist die Suchabfrage. Welches gibt zwei Tabellen zurück. Die erste ist eine Zusammenfassung, also die Gesamtzahl der Feiertage, die Ihren Kriterien entsprechen, und wie viele einzigartige Eigenschaften. Die zweite Tabelle enthält die tatsächlichen Ergebnisse der Suche.
--Build a temp table, and store everything we need in it
CREATE TABLE #Pricing (PropertyId int, Duration int, HolidayId int, Rating int, Price int, StartDate datetime, PropertyRow int);
INSERT INTO #Pricing
SELECT
PropertyId, Duration, [Id], [Rating], [Price], DepartureDate,
ROW_NUMBER() OVER (PARTITION BY PropertyId ORDER BY Price ASC) as PropertyRow
FROM
dbo.Holiday
WHERE
DepartureDate > GETDATE() AND Country = 'FR'
--Get a total number of holidays, and total number of properties
SELECT
COUNT(*) AS TotalHolidaysCount,
COUNT(DISTINCT PropertyId) AS PropertyCount
FROM
#Pricing
--Build the final table, which will contain all the holidays we actually want to return
DECLARE @FinalResults TABLE (HolidayId int, RowNumber int);
INSERT INTO
@FinalResults
SELECT
HolidayId, RowNumber
FROM
(SELECT
PropertyRow, HolidayId,
ROW_NUMBER() OVER (order by (CASE WHEN StartDate <= '01/Apr/2013' THEN 1 ELSE 0 END) ASC, [Price] ASC) as RowNumber
FROM
#Pricing
WHERE
PropertyRow = 1) as SearchResults
WHERE
(RowNumber > (10 * (1 - 1)) and RowNumber <= (1 * 10))
ORDER BY
RowNumber;
SELECT
*
FROM
@FinalResults
INNER JOIN dbo.Holiday ON HolidayId = Holiday.Id
DROP TABLE #Pricing
Jetzt könnte ich mich mit der Indizierung befassen, die offensichtlich die Leistung verbessern würde. Was mich jedoch beunruhigt, ist die unglaubliche Verwendung von temporären Tischen. Sicherlich sollte das nicht so sein, wie es gemacht wird? Das Durchsuchen der letztendlich winzigen Datenmenge dauert 5 Sekunden. Sie werden nur deshalb verwendet, weil später auf die Daten verwiesen werden muss.
Wäre es vielleicht sinnvoll, die Abfrage zweimal auszuführen, anstatt alle Daten im Speicher zu speichern? Es scheint eine Verschwendung zu sein, immer wieder über 25% der Tabelle im Speicher auszuwählen.
Jedes hilfreiche Feedback wäre dankbar. Ich suche nicht nach der 'Antwort', sondern nur nach Hilfe.
Vielen Dank, Dean
quelle
(RowNumber > (10 * (1 - 1)) and RowNumber <= (1 * 10))
viel besser geschrieben alsRowNumber Between 1 and 10
Antworten:
Es ist sehr schwierig, eine Lösung ohne die Möglichkeit, Tests auszuführen oder zu sehen, wie die Datenbank indiziert ist usw., genau vorzuschlagen. Aber ich werde es trotzdem versuchen.
Idealerweise müssen Sie ein Gleichgewicht finden. Wenn Ihre Abfrage wahrscheinlich viele Daten zurückgibt und schnell ausgeführt wird, würde ich die Abfrage in der Haupttabelle zweimal ausführen, wenn es wahrscheinlich lange dauert und eine relativ kleine zurückgibt Anzahl der Zeilen würde ich dann beim temporären Tabellenansatz bleiben.
Angesichts der Informationen, die Sie in der Frage angegeben haben, scheint es kein Problem mit der Geschwindigkeit der Auswahl zu geben. In diesem Fall stimme ich Ihnen eher zu, die zusätzlichen Kosten für das Einfügen in eine temporäre Tabelle und das anschließende Auswählen aus der temporären Tabelle Tabelle ist so viel Aufwand wie zweimaliges Ausführen der Auswahlabfrage. Die Abfragen können wie folgt vereinfacht werden:
Wenn Sie feststellen, dass dies ein Leistungseinbruch ist und Sie die Ergebnisse der Auswahl lieber zwischenspeichern möchten, würde ich eher Tabellenvariablen anstelle von temporären Tabellen verwenden und nur den Primärschlüssel für die Urlaubs-ID speichern und schnell wieder zum Urlaub zurückkehren indizierter Join von Primärschlüssel = Primärschlüssel wie folgt:
Auf diese Weise werden so wenig Daten wie möglich zwischengespeichert (eine Spalte mit Ganzzahlen), während immer noch genügend Daten für eine schnelle indizierte Suche auf dbo.Holiday gespeichert sind.
Letztendlich muss es darum gehen, Ihre Ausführungspläne zu überprüfen, geeignete Indizes zu erstellen und verschiedene Ansätze zu testen, um den für Sie am besten geeigneten zu finden.
quelle
Ohne Indizes müssen jedes Mal, wenn die Suchabfrage ausgeführt wird, alle 2 Millionen Datensätze durchsucht werden, um die 650K-FR-Instanzen zu finden. Mit Indizes kann die Datenbank im Wesentlichen direkt zu ihnen gehen. Selbst wenn Sie die Suchabfrage unverändert lassen, können Sie mit geeigneten Indizes die Geschwindigkeit verbessern.
Was die temporäre Tabelle betrifft, verstehe ich wirklich nicht, warum dies in der endgültigen Ergebnisabfrage nicht als Sub durchgeführt werden konnte. Abgesehen davon denke ich, dass temporäre Tabellen für dauerhafte Verbindungen zur Datenbank oder für Benutzerpools nützlicher wären. Wenn Sie nur die temporäre Tabelle erstellen und sie sofort zerstören, wird sie im Grunde nur als Unterabfrage verwendet.
Update: M_M macht einen guten Punkt in seinem Kommentar zu dieser Antwort. Ich bin jedoch immer noch der Meinung, dass ein Index besser wäre, wenn der Großteil der Aktivitäten nicht nur auf Sets erfolgt, bei denen das Land das einzige Kriterium ist. Für mich (nur meine Meinung) würde es darauf ankommen, wie oft die 'FR'-Teilmenge für sich allein ohne andere Kriterien benötigt würde. Andernfalls könnten Indizes für die Mehrheit der Suchvorgänge verwendet werden.
quelle