it-swarm.com.de

Optimieren von Abfragen für mehr als 25 Millionen Zeilen

Ich verwende MS SQL und muss mehrere Abfragen in derselben Tabelle nach unterschiedlichen Kriterien ausführen. Zuerst habe ich jede Abfrage in der Originaltabelle ausgeführt, obwohl alle gemeinsam gefiltert wurden (d. H. Datum, Status). Dies hat viel Zeit in Anspruch genommen (ca. 2 Minuten).

Es gibt Duplikate in Datenzeilen, und alle Indizes sind NICHT CLUSTERED. Ich interessiere mich nur für 4 Spalten für meine Kriterien und das Ergebnis sollte nur die Anzahl für alle Abfragen ausgeben.

erforderliche Spalten: TABLE, FIELD, AFTER, DATE, und es gibt jeweils einen Index für DATE und TABLE.

Nachdem ich eine temporäre Tabelle mit nur den Feldern erstellt hatte, die ich benötige, ging es auf 1:40 Minuten zurück, was immer noch sehr schlecht ist.

CREATE TABLE #TEMP
(
    TABLE VARCHAR(30) NULL,
    FIELD VARCHAR(30) NULL,
    AFTER VARCHAR(1000) NULL,
    DATE DATETIME,
    SORT_ID INT IDENTITY(1,1)
)
CREATE CLUSTERED INDEX IX_ADT ON #TEMP(SORT_ID)

INSERT INTO #TEMP (TABLE, FIELD, AFTER, DATE)
    SELECT TABLE, FIELD, AFTER, DATE 
    FROM mytbl WITH (NOLOCK)
    WHERE TABLE = 'OTB' AND
    FIELD = 'STATUS'

Führen Sie dies aus -> (216598 betroffene Zeile (n))

Da nicht alle Abfragen vom Datumsbereich abhängen, habe ich ihn nicht in die Abfrage aufgenommen. Das Problem ist, dass es gut dauert über 1 Minute nur zum Einfügen. Die obige Einfügung dauerte 1:19 Minuten

Ich möchte so etwas für mehrere Abfragen ausführen:

SELECT COUNT(*) AS COUNT
FROM #TEMP
WHERE AFTER = 'R' AND
DATE >= '2014-01-01' AND
DATE <= '2015-01-01'

Es ist ein Problem mit dem Einfügen mehr als das der Auswahl, aber die Temperatur hat viel weniger Zeilen als die ursprüngliche Tabelle, was besser sein könnte, als die Tabelle mehrmals durchzugehen.

Wie kann ich das optimieren?

EDIT

Ich habe die Sortier-ID entfernt und dachte, das Problem liege hauptsächlich in der Auswahl und nicht in der Einfügung. Es war eine Vermutung.

Ich kann für keinen Index ein eindeutiges Feld erstellen, da es keine eindeutigen Felder oder Zeilen gibt.

Ich verwende SQL Server 2012.

Tabelleninfo: Es ist ein Haufen und hat die folgende Speicherplatznutzung:

name    rows        reserved    data        index_size  unused
mytbl   24869658    9204568 KB  3017952 KB  5816232 KB  370384 KB
11
Atieh

Die Frage betrifft hauptsächlich die Optimierung der select-Anweisung:

SELECT [TABLE], [FIELD], [AFTER], [DATE]
FROM mytbl WITH (NOLOCK)
WHERE [TABLE] = 'OTB' AND
[FIELD] = 'STATUS'

Entfernen der redundanten Projektionen und Hinzufügen des vermuteten dbo - Schemas:

SELECT [AFTER], [DATE] 
FROM dbo.mytbl WITH (NOLOCK)
WHERE [TABLE] = 'OTB'
AND FIELD = 'STATUS';

Ohne einen Index wie ([TABLE],[FIELD]) INCLUDE ([AFTER],[DATE]) Hat SQL Server zwei Hauptoptionen:

  1. Scannen Sie den Heap vollständig (3 GB +). oder
  2. Suchen Sie Zeilen, die mit [TABLE] = 'OTB' Und [FIELD] = 'STATUS' Übereinstimmen (mit IDX6), Und führen Sie dann eine Heap-Suche (RID) durch pro Zeile, um den [AFTER] und [DATE] Spalten.

Ob der Optimierer einen Heap-Scan oder eine Indexsuche mit RID-Suche wählt, hängt von der geschätzten Selektivität der Prädikate [TABLE] = 'OTB' Und [FIELD] = 'STATUS' Ab. Überprüfen Sie, ob die geschätzte Anzahl der Zeilen aus der Suche mit der Realität übereinstimmt. Wenn nicht, aktualisieren Sie Ihre Statistiken. Testen Sie die Abfrage mit einem Tabellenhinweis, der die Verwendung des Index erzwingt, wenn diese Bedingung einigermaßen selektiv ist. Wenn das Optimierungsprogramm derzeit die Indexsuche auswählt, testen Sie die Leistung mit einem INDEX(0) oder FORCESCAN Hinweis, um den Heap zu scannen.

Darüber hinaus können Sie versuchen, den Scan des Heaps ein wenig zu verbessern, indem Sie einen Teil des nicht genutzten Speicherplatzes (370 MB) entfernen. In SQL Server 2008 kann dies durch Neuerstellen des Heaps erfolgen. Nicht genutzter Speicherplatz in Heaps resultiert häufig aus Löschvorgängen, bei denen keine Tabellensperre vorgenommen wurde (ohne Tabellensperre werden leere Seiten nicht von einem Heap freigegeben). Tabellen, bei denen häufig gelöscht wird, werden aus diesem Grund häufig besser als Clustertabelle gespeichert.

Die Leistung des Heap-Scans hängt davon ab, wie viel der Tabelle im Speicher gespeichert ist, wie viel von der Festplatte gelesen werden muss, wie voll die Seiten sind, wie schnell der dauerhafte Speicher ist, ob der Scan E/A- oder CPU-gebunden ist ( Parallelität kann helfen).

Wenn die Leistung immer noch nicht akzeptabel ist, nachdem Sie alle oben genannten Punkte untersucht haben, versuchen Sie, einen neuen Index zu finden. Wenn in Ihrer Version von SQL Server verfügbar, wäre ein möglicher gefilterter Index für die angegebene Abfrage:

CREATE INDEX index_name
ON dbo.mytbl ([DATE],[AFTER])
WHERE [TABLE] = 'OTB'
AND [FIELD] = 'STATUS';

Berücksichtigen Sie auch die Indexkomprimierung, sofern diese verfügbar und vorteilhaft ist. Ohne einen neuen Index können Sie relativ wenig tun, um die Leistung der angegebenen Abfrage zu verbessern.

12
Paul White 9

Ich denke, es gibt einen Grund, die Indizes hier zu ändern, weil:

  • sie haben eine Aufgabe zu erledigen (diese mehreren Abfragen)
  • data Warehouse-Volumen (mehr als 25 Millionen Zeilen) und
  • ein Leistungsproblem.

Dies wäre auch ein guter Anwendungsfall für nicht in Clustern eingeführte Columnstore-Indizes, die in SQL Server 2012 eingeführt wurden, dh einige Spalten in einer großen Tabelle mit vielen Spalten zusammenfassen/aggregieren.

Obwohl diese Indizes den Nebeneffekt haben, dass die Tabelle schreibgeschützt ist (mit Ausnahme der Partitionsumschaltung), können sie die Leistung aggregierter Abfragen unter den richtigen Bedingungen verändern. Der schreibgeschützte Aspekt kann verwaltet werden, indem der Index oder einfache Partitionswechseldaten in der Tabelle gelöscht und neu erstellt werden.

Ich habe einen einfachen Prüfstand eingerichtet, um Ihr Setup nachzuahmen, und eine gute Leistungsverbesserung festgestellt:

USE tempdb
GO

SET NOCOUNT ON
GO

-- Create a large table
IF OBJECT_ID('dbo.largeTable') IS NOT NULL
DROP TABLE dbo.largeTable
GO
CREATE TABLE dbo.largeTable ( 

    [TABLE] VARCHAR(30) NULL,
    FIELD VARCHAR(30) NULL,
    [AFTER] VARCHAR(1000) NULL,
    [DATE] DATETIME,
    SORT_ID INT IDENTITY(1,1),

    pad VARCHAR(100) DEFAULT REPLICATE( '$', 100 )
)
GO

-- Populate table
;WITH cte AS (
SELECT TOP 100000 ROW_NUMBER() OVER ( ORDER BY ( SELECT 1 ) ) rn
FROM master.sys.columns c1
    CROSS JOIN master.sys.columns c2
    CROSS JOIN master.sys.columns c3
)
INSERT INTO dbo.largeTable ( [TABLE], FIELD, [AFTER], [DATE] )
SELECT 
    x.tableName, 
    y.field,
    z.[after],
    DATEADD( day, rn % 1111, '1 Jan 2012' )
FROM cte c
    CROSS JOIN ( VALUES ( 'OTB' ), ( 'AAA' ), ( 'BBB' ), ( 'CCCC' ) ) x ( tableName )
    CROSS JOIN ( VALUES ( 'STATUS' ), ( 'TIME' ), ( 'POWER' ) ) y ( field )
    CROSS JOIN ( VALUES ( 'R' ), ( 'X' ), ( 'Z' ), ( 'A' ) ) z ( [after] )

CHECKPOINT

GO 5

EXEC sp_spaceused 'dbo.largeTable'
GO

SELECT MIN([DATE]) xmin, MAX([DATE]) xmax, FORMAT( COUNT(*), '#,#' ) records
FROM dbo.largeTable
GO

-- Optionally clear cache for more comparable results; DO NOT RUN ON PRODUCTION SYSTEM!!
--DBCC DROPCLEANBUFFERS
--DBCC FREEPROCCACHE
--GO

DECLARE @startDate DATETIME2 = SYSUTCDATETIME()

SELECT COUNT(*) AS COUNT
FROM dbo.largeTable
WHERE [AFTER] = 'R' 
  AND [DATE] >= '2014-01-01' 
  AND [DATE] <= '2015-01-01'

SELECT DATEDIFF( millisecond, @startDate, SYSUTCDATETIME() ) diff1
GO

-- Add the non-clustered columnstore
CREATE NONCLUSTERED COLUMNSTORE INDEX _cs ON dbo.largeTable ( [TABLE], FIELD, [AFTER], [DATE] )
GO

-- Optionally clear cache for more comparable results; DO NOT RUN ON PRODUCTION SYSTEM!!
--DBCC DROPCLEANBUFFERS
--DBCC FREEPROCCACHE
--GO

-- Check query again
DECLARE @startDate DATETIME2 = SYSUTCDATETIME()

SELECT COUNT(*) AS COUNT
FROM dbo.largeTable
WHERE [AFTER] = 'R' 
  AND [DATE] >= '2014-01-01' 
  AND [DATE] <= '2015-01-01'

SELECT DATEDIFF( millisecond, @startDate, SYSUTCDATETIME() ) diff2
GO

Meine Ergebnisse, 6 Sekunden v 0,08 Sekunden:

enter image description here

Versuchen Sie zusammenfassend, mit Ihrem Chef einen Fall zu erstellen, in dem die Indizes geändert werden, oder erstellen Sie zumindest eine Art Übernachtprozess, bei dem diese Datensätze in eine schreibgeschützte Berichtstabelle/Datenbank umgewandelt werden, in der Sie Ihre Arbeit erledigen und die Indizierung hinzufügen können geeignet für diese Arbeitsbelastung.

6
wBob