In meiner Anwendung muss ich Tabellen mit Millionen von Zeilen verbinden. Ich habe eine Frage wie diese:
SELECT DISTINCT "f"."id" AS "FileId"
, "f"."name" AS "FileName"
, "f"."year" AS "FileYear"
, "vt"."value" AS "value"
FROM files "f"
JOIN "clients" "cl" ON("f"."cid" = "cl"."id" AND "cl"."id" = 10)
LEFT JOIN "value_text" "vt" ON ("f"."id" = "vt"."id_file" AND "vt"."id_field" = 65739)
GROUP BY "f"."id", "f"."name", "f"."year", "vt"."value"
Die Tabelle "files" hat 10 Millionen Zeilen und die Tabelle "value_text" hat 40 Millionen Zeilen.
Diese Abfrage ist zu langsam. Die Ausführung dauert zwischen 40 Sekunden (15000 Ergebnisse) und 3 Minuten (65000 Ergebnisse).
Ich hatte darüber nachgedacht, die beiden Abfragen zu teilen, kann es aber nicht, weil ich manchmal nach der verbundenen Spalte (Wert) bestellen muss ...
Was kann ich machen? Ich verwende SQL Server mit Azure. Insbesondere Azure SQL-Datenbank mit Preis- / Modellstufe "PRS1 PremiumRS (125 DTUs)" .
Ich erhalte viele Daten, aber ich denke, die Internetverbindung ist kein Engpass, da ich bei anderen Abfragen auch viele Daten erhalte und diese schneller sind.
Ich habe versucht, die Client-Tabelle als Unterabfrage zu verwenden und DISTINCT
mit den gleichen Ergebnissen zu entfernen .
Ich habe 1428 Zeilen in der Client-Tabelle.
zusätzliche Information
clients
Tabelle:
CREATE TABLE [dbo].[clients](
[id] [bigint] IDENTITY(1,1) NOT NULL,
[code] [nvarchar](70) NOT NULL,
[password] [nchar](40) NOT NULL,
[name] [nvarchar](150) NOT NULL DEFAULT (N''),
[email] [nvarchar](255) NULL DEFAULT (NULL),
[entity] [int] NOT NULL DEFAULT ((0)),
[users] [int] NOT NULL DEFAULT ((0)),
[status] [varchar](8) NOT NULL DEFAULT ('inactive'),
[created] [datetime2](7) NULL DEFAULT (getdate()),
[activated] [datetime2](7) NULL DEFAULT (getdate()),
[client_type] [varchar](10) NOT NULL DEFAULT ('normal'),
[current_size] [bigint] NOT NULL DEFAULT ((0)),
CONSTRAINT [PK_clients_id] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON),
CONSTRAINT [clients$code] UNIQUE NONCLUSTERED
(
[code] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
files
Tabelle:
CREATE TABLE [dbo].[files](
[id] [bigint] IDENTITY(1,1) NOT NULL,
[cid] [bigint] NOT NULL DEFAULT ((0)),
[eid] [bigint] NOT NULL DEFAULT ((0)),
[year] [bigint] NOT NULL DEFAULT ((0)),
[name] [nvarchar](255) NOT NULL DEFAULT (N''),
[extension] [int] NOT NULL DEFAULT ((0)),
[size] [bigint] NOT NULL DEFAULT ((0)),
[id_doc] [bigint] NOT NULL DEFAULT ((0)),
[created] [datetime2](7) NULL DEFAULT (getdate())
CONSTRAINT [PK_files_id] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON),
CONSTRAINT [files$estructure_unique] UNIQUE NONCLUSTERED
(
[year] ASC,
[name] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
GO
ALTER TABLE [dbo].[files] WITH NOCHECK ADD CONSTRAINT [FK_files_client] FOREIGN KEY([cid])
REFERENCES [dbo].[clients] ([id])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[files] CHECK CONSTRAINT [FK_files_client]
GO
value_text
Tabelle:
CREATE TABLE [dbo].[value_text](
[id] [bigint] IDENTITY(1,1) NOT NULL,
[id_file] [bigint] NOT NULL DEFAULT ((0)),
[id_field] [bigint] NOT NULL DEFAULT ((0)),
[value] [nvarchar](255) NULL DEFAULT (NULL),
[id_doc] [bigint] NULL DEFAULT (NULL)
CONSTRAINT [PK_value_text_id] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
GO
ALTER TABLE [dbo].[value_text] WITH NOCHECK ADD CONSTRAINT [FK_valuesT_field] FOREIGN KEY([id_field])
REFERENCES [dbo].[fields] ([id])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[value_text] CHECK CONSTRAINT [FK_valuesT_field]
GO
Ausführungsplan:
* Ich habe die Tabellen und Felder in dieser Frage zum allgemeinen Verständnis übersetzt. In diesem Bild entspricht "archivos" "files", "clientes" von "clients" und "valores_texto" von "value_text".
Ausführungsplan ohne DISTINCT
:
Ausführungsplan ohne DISTINCT
und GROUP BY
(etwas schneller abfragen):
Abfragetest (Antwort von Krismorte)
Dies ist der Ausführungsplan der Abfrage, der langsamer als zuvor ist. Hier gibt mir die Abfrage über 400.000 Zeilen zurück, aber selbst wenn die Ergebnisse paginiert werden, gibt es keine Änderungen.
Ausführungsplan detaillierter: https://www.brentozar.com/pastetheplan/?id=By_UC2aBG
Und dies ist der Ausführungsplan der Abfrage, der schneller als zuvor ist. Hier gibt die Abfrage über 65.000 Zeilen zurück.
Ausführungsplan detaillierter: https://www.brentozar.com/pastetheplan/?id=r116e6pSM
Antworten:
Ich denke, Sie brauchen diesen Index (wie Krismorte vorgeschlagen hat ):
Der folgende Index ist wahrscheinlich nicht erforderlich, da Sie anscheinend über einen geeigneten vorhandenen Index verfügen (in der Frage nicht erwähnt), der Vollständigkeit halber füge ich ihn jedoch hinzu:
Drücken Sie die Abfrage aus als:
Dies sollte einen Ausführungsplan wie folgt ergeben:
Das
OPTION (RECOMPILE)
ist optional. Fügen Sie nur hinzu, wenn Sie feststellen, dass die ideale Planform für verschiedene Parameterwerte unterschiedlich ist. Es gibt andere mögliche Lösungen für solche "Parameter-Sniffing" -Probleme.Mit dem neuen Index können Sie auch feststellen, dass der ursprüngliche Abfragetext einen sehr ähnlichen Plan erzeugt, auch mit guter Leistung.
Möglicherweise müssen Sie auch die Statistiken in der
files
Tabelle aktualisieren , da die Schätzung im mitgelieferten Plan fürcid = 19
nicht korrekt ist:Wenn Sie der Dateitabelle weitere Spalten hinzufügen (und diese in Ihrer Abfrage verwenden / zurückgeben), müssen Sie sie dem Index hinzufügen (mindestens als eingeschlossene Spalten), damit der Index "bedeckt" bleibt. Andernfalls scannt der Optimierer möglicherweise die Dateitabelle, anstatt die im Index nicht vorhandenen Spalten nachzuschlagen. Sie können
cid
stattdessen auch einen Teil eines Clustering-Index für diese Tabelle erstellen. Es hängt davon ab, ob. Stellen Sie eine neue Frage, wenn Sie diese Punkte klären möchten.quelle
Nun, diese Abfrage war ziemlich schwierig. Ich ändere die Filterordnungen und erstelle zwei Deckungsindizes
die Abfrage
Ergebnisabfrageplan
Versuchen Sie dies, ich hoffe, das wird genug sein
quelle