Hallo.
Ich habe die Aufgabe erhalten, die SQL-Anweisungen auf einer stark frequentierten Internetseite zu optimieren. Mein Problem ist eine einzelne SELECT-Abfrage anzupassen. Diese funktioniert bei kleinen Datenmengen (bis 50.000 Datensätze pro involvierte Tabelle) bis auf kleine Performanceprobleme gut. Allerdings haben wir in einer Tabelle von den 5 ca. 600.000 Datensätze. Das Tabellenschema steht in der nächsten Antwort.
Die beiden Tabellen "document" und "lng" sind nicht für das Problem verantwortlich und wurden daher von mir nur der Vollständigkeit wegen (ohne Details) angegeben.
Die alte Abfrage versagte. Durch verschiedene Testreihen (entfernen einzelner Bestandteile aus der Abfrage) konnte ich feststellen dass das Problem folgendes ist:
Und zwar muss aus der Tabelle "user" der Benutzername (LoginName) mit Hilfe der in der Tabelle "forumthreadentry" eingetragenen Benutzerid (AuthorId) ausgelsen werden. Dies dauert einfach viel zu lange (bis zu 3 Minuten).
Noch zur weiteren Erklärung: Diese Abfrage zeigt die Übersicht der in einem Topic verfassten Threads an. Diese Threads werden nach der letzten geschriebenen Antwort chronologisch absteigend sortiert. Pro Seite werden 30 Threads angezeigt (dieser Umstand wirkt sich aber nicht auf die Zeit aus. Die Zeit bleibt gleich ob mit oder ohne LIMIT).
Außerdem wäre es schön die ganzen SUBSELECTS aus der Abfrage zu verbannen (sofern möglich).
Hier die alte Abfrage:
Und hier meine derzeit aktuellste Abfrage:
Dazu gehört auch die folgende Funktion:
Ich hoffe das ich genügend Informationen zur Verfügung gestellt habe und das ihr mir helfen könnt.
Gruß Oli
Ich habe die Aufgabe erhalten, die SQL-Anweisungen auf einer stark frequentierten Internetseite zu optimieren. Mein Problem ist eine einzelne SELECT-Abfrage anzupassen. Diese funktioniert bei kleinen Datenmengen (bis 50.000 Datensätze pro involvierte Tabelle) bis auf kleine Performanceprobleme gut. Allerdings haben wir in einer Tabelle von den 5 ca. 600.000 Datensätze. Das Tabellenschema steht in der nächsten Antwort.
Die beiden Tabellen "document" und "lng" sind nicht für das Problem verantwortlich und wurden daher von mir nur der Vollständigkeit wegen (ohne Details) angegeben.
Die alte Abfrage versagte. Durch verschiedene Testreihen (entfernen einzelner Bestandteile aus der Abfrage) konnte ich feststellen dass das Problem folgendes ist:
Und zwar muss aus der Tabelle "user" der Benutzername (LoginName) mit Hilfe der in der Tabelle "forumthreadentry" eingetragenen Benutzerid (AuthorId) ausgelsen werden. Dies dauert einfach viel zu lange (bis zu 3 Minuten).
Noch zur weiteren Erklärung: Diese Abfrage zeigt die Übersicht der in einem Topic verfassten Threads an. Diese Threads werden nach der letzten geschriebenen Antwort chronologisch absteigend sortiert. Pro Seite werden 30 Threads angezeigt (dieser Umstand wirkt sich aber nicht auf die Zeit aus. Die Zeit bleibt gleich ob mit oder ohne LIMIT).
Außerdem wäre es schön die ganzen SUBSELECTS aus der Abfrage zu verbannen (sofern möglich).
Hier die alte Abfrage:
Code:
SELECT
forumthread.Id
,forumthread.Locked
,forumthread.SolvedState
,forumthread.Timestamp
,forumthread.Title
,forumthread.ViewCount
,forumthreadentry.AllowHtml
,forumthreadentry.ImageId
,forumthreadentry.Text
,forumthreadentry.Timestamp
,(SELECT
COUNT(forumthreadentryCount.Id)
FROM
forumthreadentry AS forumthreadentryCount
WHERE
forumthreadentryCount.ThreadId = forumthread.Id
LIMIT 1) AS forumthreadentryCount
,(SELECT
COUNT(forumthreadentryCount2.Id)
FROM
forumthreadentry AS forumthreadentryCount2
WHERE
forumthreadentryCount2.AuthorId = @userId
AND
forumthreadentryCount2.ThreadId = forumthread.Id
) AS forumthreadentryCount2
,forumthreadentryUser.Id
,forumthreadentryUser.LoginName
,forumthreadUser.Id
,forumthreadUser.LoginName
,forumthread.LngId AS LngId
,flagDocument.Id AS LngFlagId
,flagDocument.Extension AS LngFlagExtension
,forumthreadentrylast.Timestamp AS LastEntryTimeStamp
FROM
forumthread
LEFT JOIN
forumthreadentry AS forumthreadentrylast
ON
forumthreadentrylast.Id = (SELECT
forumthreadentryUserSelect.Id
FROM
forumthreadentry AS forumthreadentryUserSelect
WHERE
forumthreadentryUserSelect.ThreadId = forumthread.Id
ORDER BY
forumthreadentryUserSelect.Timestamp DESC
LIMIT 1)
LEFT JOIN
forumthreadentry
ON
forumthreadentry.ThreadId = forumthread.Id
LEFT JOIN
user AS forumthreadentryUser
ON
forumthreadentryUser.Id = forumthreadentrylast.AuthorId
JOIN
user AS forumthreadUser
ON
forumthreadUser.Id = forumthread.AuthorId
LEFT JOIN
lng AS forumthreadLng
ON
forumthreadLng.Id = forumthread.LngId
LEFT JOIN
document AS flagDocument
ON flagDocument.Id = forumthreadLng.SmallFlagImage
WHERE
forumthread.TopicId = @forumTopicId
GROUP BY
forumthread.Id
ORDER BY
forumthreadentrylast.Timestamp DESC
,forumthread.Timestamp DESC
LIMIT
0
,30;
Code:
SELECT forumthread.Id ,forumthread.Title ,forumthread.Locked ,forumthread.SolvedState ,forumthread.Timestamp AS Open_Timestamp ,MAX(forumthreadentry.Timestamp) AS LastPost_Timestamp ,forumthreadentry.AuthorId ,user.LoginName ,forumthread.ViewCount ,f_countthreads(forumthreadentry.ThreadId) AS counter2 ,forumthreadentry.AllowHtml ,forumthreadentry.ImageId ,forumthread.LngId AS LngId ,document.Id AS LngFlagId ,document.Extension AS LngFlagExtension FROM forumthreadentry LEFT JOIN forumthread ON forumthread.Id = forumthreadentry.ThreadId LEFT JOIN user ON user.Id = forumthreadentry.AuthorId LEFT JOIN lng ON lng.Id = forumthread.LngId LEFT JOIN document ON document.Id = lng.SmallFlagImage WHERE forumthread.TopicId = @forumTopicId GROUP BY forumthreadentry.ThreadId ORDER BY LastPost_Timestamp DESC LIMIT 0 ,30;
Code:
DELIMITER $$
DROP FUNCTION IF EXISTS `f_countthreads` $$
CREATE DEFINER=`root`@`localhost` FUNCTION `f_countthreads`(ThreadId INT) RETURNS int(11)
BEGIN
DECLARE counter INT;
SELECT
COUNT(forumthreadentry.ThreadId) INTO counter
FROM
forumthreadentry
WHERE
forumthreadentry.ThreadId = ThreadId
LIMIT 1;
RETURN counter;
END $$
DELIMITER
Gruß Oli

Kommentar