Massive CROSS JOIN in SQL Server 2005
-
21-08-2019 - |
Frage
Ich bin Portierung ein Prozess, der eine MASSIVE CROSS JOIN
von zwei Tabellen erstellt. Die resultierende Tabelle enthält 15m Datensätze (sieht aus wie der Prozess ein 30m Cross-Join mit einem 2600 Reihe Tisch und 12000 Reihe Tisch macht und dann hat einige Gruppierung, die es in zwei Hälften geteilt werden). Die Reihen sind relativ schmal - nur 6 Spalten. Es wurde ohne ein Zeichen der Fertigstellung für 5 Stunden ausgeführt wird. Ich habe nur bemerkt, nur die Anzahl Diskrepanz zwischen den guten bekannt und was würde ich für das Kreuz erwarten verbinden, so dass mein Ausgang nicht über die Gruppierung oder deduping, die den Final Table halbieren - dies scheint aber immer noch wie es nicht geht zu vervollständigen Zeit bald.
Zuerst werde ich sehe diese Tabelle, wenn möglich aus dem Prozess zu beseitigen - offensichtlich konnte es durch den Beitritt zu den beiden Tabellen einzeln ausgetauscht werden, aber im Moment habe ich nicht in Sicht überall sonst wird es verwendet <. / p>
Aber da der bestehende Prozess tut es (in weniger Zeit, auf einer weniger leistungsfähige Maschine, mit der FOCUS-Sprache), gibt es Möglichkeiten zur Verbesserung der Leistung der großen CROSS JOIN
s in SQL Server (2005) (Hardware ist nicht wirklich eine Option, ist dieses Feld ein 64-Bit-8-Wege mit 32-GB RAM)?
Details:
Es ist auf diese Weise in FOCUS geschrieben (Ich versuche, die gleiche Leistung zu erzeugen, die ein CROSS JOIN in SQL ist):
JOIN CLEAR *
DEFINE FILE COSTCENT
WBLANK/A1 = ' ';
END
TABLE FILE COSTCENT
BY WBLANK BY CC_COSTCENT
ON TABLE HOLD AS TEMPCC FORMAT FOCUS
END
DEFINE FILE JOINGLAC
WBLANK/A1 = ' ';
END
TABLE FILE JOINGLAC
BY WBLANK BY ACCOUNT_NO BY LI_LNTM
ON TABLE HOLD AS TEMPAC FORMAT FOCUS INDEX WBLANK
JOIN CLEAR *
JOIN WBLANK IN TEMPCC TO ALL WBLANK IN TEMPAC
DEFINE FILE TEMPCC
CA_JCCAC/A16=EDIT(CC_COSTCENT)|EDIT(ACCOUNT_NO);
END
TABLE FILE TEMPCC
BY CA_JCCAC BY CC_COSTCENT AS COST CENTER BY ACCOUNT_NO
BY LI_LNTM
ON TABLE HOLD AS TEMPCCAC
END
So die erforderliche Ausgabe wirklich ein CROSS JOIN ist (es ist eine leere Spalte von jeder Seite verbinden).
In SQL:
CREATE TABLE [COSTCENT](
[COST_CTR_NUM] [int] NOT NULL,
[CC_CNM] [varchar](40) NULL,
[CC_DEPT] [varchar](7) NULL,
[CC_ALSRC] [varchar](6) NULL,
[CC_HIER_CODE] [varchar](20) NULL,
CONSTRAINT [PK_LOOKUP_GL_COST_CTR] PRIMARY KEY NONCLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY
= OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [JOINGLAC](
[ACCOUNT_NO] [int] NULL,
[LI_LNTM] [int] NULL,
[PR_PRODUCT] [varchar](5) NULL,
[PR_GROUP] [varchar](1) NULL,
[AC_NAME_LONG] [varchar](40) NULL,
[LI_NM_LONG] [varchar](30) NULL,
[LI_INC] [int] NULL,
[LI_MULT] [int] NULL,
[LI_ANLZ] [int] NULL,
[LI_TYPE] [varchar](2) NULL,
[PR_SORT] [varchar](2) NULL,
[PR_NM] [varchar](26) NULL,
[PZ_SORT] [varchar](2) NULL,
[PZNAME] [varchar](26) NULL,
[WANLZ] [varchar](3) NULL,
[OPMLNTM] [int] NULL,
[PS_GROUP] [varchar](5) NULL,
[PS_SORT] [varchar](2) NULL,
[PS_NAME] [varchar](26) NULL,
[PT_GROUP] [varchar](5) NULL,
[PT_SORT] [varchar](2) NULL,
[PT_NAME] [varchar](26) NULL
) ON [PRIMARY]
CREATE TABLE [JOINCCAC](
[CA_JCCAC] [varchar](16) NOT NULL,
[CA_COSTCENT] [int] NOT NULL,
[CA_GLACCOUNT] [int] NOT NULL,
[CA_LNTM] [int] NOT NULL,
[CA_UNIT] [varchar](6) NOT NULL,
CONSTRAINT [PK_JOINCCAC_KNOWN_GOOD] PRIMARY KEY CLUSTERED
(
[CA_JCCAC] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY
= OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Mit dem SQL-Code:
INSERT INTO [JOINCCAC]
(
[CA_JCCAC]
,[CA_COSTCENT]
,[CA_GLACCOUNT]
,[CA_LNTM]
,[CA_UNIT]
)
SELECT Util.PADLEFT(CONVERT(varchar, CC.COST_CTR_NUM), '0',
7)
+ Util.PADLEFT(CONVERT(varchar, GL.ACCOUNT_NO), '0',
9) AS CC_JCCAC
,CC.COST_CTR_NUM AS CA_COSTCENT
,GL.ACCOUNT_NO % 900000000 AS CA_GLACCOUNT
,GL.LI_LNTM AS CA_LNTM
,udf_BUPDEF(GL.ACCOUNT_NO, CC.COST_CTR_NUM, GL.LI_LNTM, 'N') AS CA_UNIT
FROM JOINGLAC AS GL
CROSS JOIN COSTCENT AS CC
Je nachdem, wie diese Tabelle anschließend verwendet wird, soll es in der Lage sein, aus dem Prozess eliminiert werden, indem man einfach seinen Wechsel sowohl die ursprünglichen Tabellen verwendet, um ihn zu bauen. Dies ist jedoch ein extrem großer Portierungsaufwand, und ich könnte nicht die Verwendung der Tabelle für einige Zeit finden, so dass ich frage mich, ob es irgendwelche Tricks waren große Tische wie in einer zeitgemäßen Weise CROSS JOIN
ing (zumal die bestehenden Verfahren in FOCUS in der Lage, es schnell zu tun). Auf diese Weise konnte ich die Richtigkeit meines Bau der Ersatz-Abfrage validieren und sie dann später mit Blick ausklammern oder was auch immer.
Ich bin auch unter Berücksichtigung der UDF und String-Manipulation Ausklammern und Durchführen der CROSS erste JOIN ein wenig den Prozess zu brechen.
Die bisherigen Ergebnisse:
Es stellt sich heraus, dass die UDF viel beitragen kann (negativ) auf die Leistung. Aber es scheint auch ein großer Unterschied zwischen einer 15m Reihe zu sein Kreuz verbinden und einem 30m Reihe Kreuz verbinden. Ich habe keine Rechte SHOWPLAN (boo hoo), so kann ich nicht sagen, ob der Plan ist es mit besser oder schlechter ist nach Indizes zu ändern. Ich habe es noch nicht Refactoring, aber erwarte die gesamte Tabelle kurz weg zu gehen.
Lösung
die Abfrage Prüfungs zeigen nur eine Spalte aus einer Tabelle verwendet, und nur zwei Spalten aus der anderen Tabelle verwendet. Aufgrund der sehr geringen Anzahl von Spalten verwendet wird, kann diese Abfrage einfach mit Deck- Indizes verbessert werden:
CREATE INDEX COSTCENTCoverCross ON COSTCENT(COST_CTR_NUM)
CREATE INDEX JOINGLACCoverCross ON JOINGLAC(ACCOUNT_NO, LI_LNTM)
Hier sind meine Fragen zur weiteren Optimierung:
Wenn Sie die Abfrage in Query Analyzer setzen und Whack die „Show geschätzten Ausführungsplan“ Taste, wird es eine grafische Darstellung zeigen, was es tun wird.
Join-Typ: Es sollte eine verschachtelte Schleife dort beitreten wird. (Die anderen Optionen sind fusionieren verbinden und Hashverknüpfung). Wenn Sie verschachtelte Schleife zu sehen, dann ok. Wenn Sie sehen, verschmelzen beitreten oder Hashverknüpfung, lassen Sie es uns wissen.
Reihenfolge der Tabellenzugriff: Gehen den ganzen Weg nach oben und bewegen den ganzen Weg nach rechts. Der erste Schritt soll eine Tabelle zugreifen. Welche Tabelle ist, dass und welche Methode verwendet wird (Index-Scan, gruppierten Index-Scan)? Welche Methode wird verwendet, um die andere Tabelle zuzugreifen?
Parallelismus: Sie sollten die kleinen jaggedy Pfeile auf fast alle Symbole im Plan angezeigt, dass Parallelität verwendet wird. Wenn Sie dies nicht sehen, es ist ein großes Problem!
Das udf_BUPDEF mich betrifft. Ist es aus zusätzlichen Tabellen lesen? Util.PADLEFT betrifft mich weniger, aber immer noch .. was ist es? Wenn es nicht ein Datenbankobjekt ist, dann erwägen, mit dieser statt:
RIGHT('z00000000000000000000000000' + columnName, 7)
Gibt es irgendwelche Trigger auf JOINCCAC? Wie wäre es Indizes? Mit einem Einsatz dieses große, werden Sie alle Trigger und Indizes für diese Tabelle löschen wollen.
Andere Tipps
Weiter auf, was andere ein Wort, Funktionen DB, die Abfragen enthalten, die immer in einem ausgewählten verwendet werden, machte meine Abfragen extrem langsam. Aus der Spitze von meinem Kopf, ich glaube, dass ich eine Abfrage hatte in 45 Sekunden lief, dann entfernte ich die Funktion, und dann Ergebnis 0 Sekunden waren:)
So überprüfen udf_BUPDEF wird keine Anfragen zu tun.
Überwinden Sie die Abfrage es ein einfaches einfaches Kreuz verbinden zu machen.
SELECT CC.COST_CTR_NUM, GL.ACCOUNT_NO
,CC.COST_CTR_NUM AS CA_COSTCENT
,GL.ACCOUNT_NO AS CA_GLACCOUNT
,GL.LI_LNTM AS CA_LNTM
-- I don't know what is BUPDEF doing? but remove it from the query for time being
-- ,udf_BUPDEF(GL.ACCOUNT_NO, CC.COST_CTR_NUM, GL.LI_LNTM, 'N') AS CA_UNIT
FROM JOINGLAC AS GL
CROSS JOIN COSTCENT AS CC
Sehen Sie, wie gut das einfache Kreuz verbinden? (Ohne irgendwelche Funktionen auf sie angewendet wird)