Kom ihåg mig?

Vad är fel i min SQL?

 
 
Ämnesverktyg Visningsalternativ
Oläst 2013-01-31, 13:30 #1
Clarence Clarence är inte uppkopplad
Administratör
 
Reg.datum: Jan 2003
Inlägg: 1 974
Clarence Clarence är inte uppkopplad
Administratör
 
Reg.datum: Jan 2003
Inlägg: 1 974
Citat:
Ursprungligen postat av ConnyWesth Visa inlägg
Kod:
SELECT threadid, MAX(senastedatum) as senastedatum
FROM
(
	SELECT threadid, MAX(createddate) AS senastedatum from wn.threads
	GROUP BY threadid

	UNION 

	SELECT threadid, MAX(created)  AS senastedatum from wn.posts
	GROUP BY threadid
) x
GROUP BY threadid
ORDER BY senastedatum DESC;
Jag skulle akta mig för att använda denna metod. Så fort man får lite trafik eller datamängd så kommer den sega ner rejält. Den använder inga index och skapar en temporär tabell som görs filesort på. Möjligtvis att den kan gå rätt OK med t ex MariaDB, men med vanilla MySQL ska man vara försiktig med sådant.

Westmans idé om att uppdatera threads med senaste aktiva datum är mycket bättre.
Clarence är inte uppkopplad   Svara med citatSvara med citat
Oläst 2013-01-31, 15:23 #2
Conny Westh Conny Westh är inte uppkopplad
Klarade millennium-buggen
 
Reg.datum: Aug 2005
Inlägg: 5 166
Conny Westh Conny Westh är inte uppkopplad
Klarade millennium-buggen
 
Reg.datum: Aug 2005
Inlägg: 5 166
Citat:
Ursprungligen postat av Clarence Visa inlägg
Westmans idé om att uppdatera threads med senaste aktiva datum är mycket bättre.
Den lösningen bryter mot en av relationsdatabasteorins grundregler, nämligen redundansproblmatiken. Redundans skapar kvalitetsproblem på själva datat och ska därför undvikas till varje pris.

Min lösning löser trådskaparens problem, och gör det på ett effektivt, enkelt, lättfattligt, underhållsvänligt och tryggt sätt. Sen får trådskaparen välja själv.
Conny Westh är inte uppkopplad   Svara med citatSvara med citat
Oläst 2013-01-31, 15:41 #3
Clarence Clarence är inte uppkopplad
Administratör
 
Reg.datum: Jan 2003
Inlägg: 1 974
Clarence Clarence är inte uppkopplad
Administratör
 
Reg.datum: Jan 2003
Inlägg: 1 974
Citat:
Ursprungligen postat av ConnyWesth Visa inlägg
Den lösningen bryter mot en av relationsdatabasteorins grundregler, nämligen redundansproblmatiken. Redundans skapar kvalitetsproblem på själva datat och ska därför undvikas till varje pris.

Min lösning löser trådskaparens problem, och gör det på ett effektivt, enkelt, lättfattligt, underhållsvänligt och tryggt sätt. Sen får trådskaparen välja själv.
Denormalisering är den enklaste och i särklass mest effektiva lösningen för att lösa många prestanda-problem som kommer av normaliserad välstrukturerad data. Vill du läsa mer om detta etablerade och välanvända koncept kan du börja här: http://en.wikipedia.org/wiki/Denormalization

Just p g a av att läslasten är så mycket högre än skrivlasten blir det ett väldigt effektivt verktyg. På ett forum kan du räkna med en ratio på iaf 100:1, även om det oftare hamnar närmare 1000:1.

Om du inte vet vad det innebär att läsa resultatet från en EXPLAIN på din query så har du inte en aning om din lösning faktiskt är effektiv efter MySQLs query plan. Om du kör den och läser på om betydelsen av resultatet så kan du lätt inse att din query är väldigt ineffektiv.
Clarence är inte uppkopplad   Svara med citatSvara med citat
Oläst 2013-01-31, 22:24 #4
Conny Westh Conny Westh är inte uppkopplad
Klarade millennium-buggen
 
Reg.datum: Aug 2005
Inlägg: 5 166
Conny Westh Conny Westh är inte uppkopplad
Klarade millennium-buggen
 
Reg.datum: Aug 2005
Inlägg: 5 166
Citat:
Ursprungligen postat av Clarence Visa inlägg
Denormalisering är den enklaste och i särklass mest effektiva lösningen för att lösa många prestanda-problem som kommer av normaliserad välstrukturerad data. Vill du läsa mer om detta etablerade och välanvända koncept kan du börja här: http://en.wikipedia.org/wiki/Denormalization

Just p g a av att läslasten är så mycket högre än skrivlasten blir det ett väldigt effektivt verktyg. På ett forum kan du räkna med en ratio på iaf 100:1, även om det oftare hamnar närmare 1000:1.

Om du inte vet vad det innebär att läsa resultatet från en EXPLAIN på din query så har du inte en aning om din lösning faktiskt är effektiv efter MySQLs query plan. Om du kör den och läser på om betydelsen av resultatet så kan du lätt inse att din query är väldigt ineffektiv.
För att det över huvud taget ska vara intressant att diskutera denormalisering eller optimering som strider mot de grundläggande principerna för hur man bygger relationsdatabaser (exempelvis normalisering för unvikande av redundans) så måste man göra en kalkyl på vad den eventuella vinsten kan bli vid en genosnittlig belastning, i jämförelse med den tid det tar att utveckla denna förändring i form av mantid och kostnader. För att en optimering ska vara intressant så måste minst fyra minimikriterier vara uppfyllda (ibland behöver fler kritrier vara uppfyllda):

1 - Garanterad datakvalitet
2 - Det ska verkligen finnas ett upplevt behov dvs det måste föreligga ett kännbart prestandaproblem
3 - Den beräknade prestandavinsten ska vara avsevärd
4 - Kostnaden måste stå i rimlig proportion till den tidsvinst man beräknas göra

Jag ger mig aldrig in på optimering ur prestandasynpunkt om det inte finns ett verkligt behov av det, dvs om det är någon som upplever att systemet tar för lång tid att köra. Annars är det rent slöseri med arbetstid.

Senast redigerad av Conny Westh den 2013-01-31 klockan 22:32
Conny Westh är inte uppkopplad   Svara med citatSvara med citat
Oläst 2013-01-31, 11:21 #5
Conny Westh Conny Westh är inte uppkopplad
Klarade millennium-buggen
 
Reg.datum: Aug 2005
Inlägg: 5 166
Conny Westh Conny Westh är inte uppkopplad
Klarade millennium-buggen
 
Reg.datum: Aug 2005
Inlägg: 5 166
Jag tänkte även förklara lite hur jag tänkt när jag löste problemet.

Grundprincipen är att dela upp ett stort problem i sina atomära beståndsdelar. Det var ju från början två olika tabeller och man vill ha ut senaste datum grupperat på threadid i var och en av dessa två tabeller.

För att hämta ut senaste datum från threads-tabellen så behöver man skriva så här:
Kod:
SELECT threadid, MAX(createddate) AS senastedatum from wn.threads
GROUP BY threadid
För att få ut senaste datum från posts-tabellen skriver man så här:
Kod:
SELECT threadid, MAX(created)  AS senastedatum from wn.posts
GROUP BY threadid

Sen vill vi bara ha ut det senaste av dessa sammanslagna tabeller och då slår man bara ihop dessa tabeller med en UNION:
Kod:
SELECT threadid, MAX(createddate) AS senastedatum from wn.threads
GROUP BY threadid

UNION 

SELECT threadid, MAX(created)  AS senastedatum from wn.posts
GROUP BY threadid

Men då får vi fler rader per thread och det vill vi inte ha utan endast ett datum per thread. Då behöver vi göra ytterligare en gruppering. Men Group By funkar bara på EN tabell så vi måste först skapa en enda tabell av denna UNION-statement, vi ger tabellen ett alias som 'x':
Kod:
SELECT *
FROM
(
    SELECT threadid, MAX(createddate) AS senastedatum from wn.threads
    GROUP BY threadid

    UNION 

    SELECT threadid, MAX(created)  AS senastedatum from wn.posts
    GROUP BY threadid
) x

Och sen gör vi bara en gruppering och bakvänd sortering på hela kalaset, så var det fixat, lätt som en plätt:
Kod:
SELECT threadid, MAX(senastedatum) as senastedatum
FROM
(
	SELECT threadid, MAX(createddate) AS senastedatum from wn.threads
	GROUP BY threadid

	UNION 

	SELECT threadid, MAX(created)  AS senastedatum from wn.posts
	GROUP BY threadid
) x
GROUP BY threadid
ORDER BY senastedatum DESC;

Senast redigerad av Conny Westh den 2013-01-31 klockan 11:27
Conny Westh är inte uppkopplad   Svara med citatSvara med citat
Oläst 2013-01-31, 12:14 #6
Conny Westh Conny Westh är inte uppkopplad
Klarade millennium-buggen
 
Reg.datum: Aug 2005
Inlägg: 5 166
Conny Westh Conny Westh är inte uppkopplad
Klarade millennium-buggen
 
Reg.datum: Aug 2005
Inlägg: 5 166
Det kan ju vara lite smart att lägga upp en StoredProcedure så det blir enkelt att anropa denna procedure om man använder den på fler ställen:

Kod:
-- --------------------------------------------------------------------------------
-- Routine DDL
-- Note: comments before and after the routine body will not be stored by the server
-- --------------------------------------------------------------------------------
DELIMITER $$

CREATE DEFINER=`root`@`localhost` PROCEDURE `ListOfThreadsByLatestUpdate`()
BEGIN
	SELECT threadid, MAX(senastedatum) as senastedatum
	FROM
	(
		SELECT threadid, MAX(createddate) AS senastedatum from wn.threads
		GROUP BY threadid
		UNION 
		SELECT threadid, MAX(created)  AS senastedatum from wn.posts
		GROUP BY threadid
	) x
	GROUP BY threadid
	ORDER BY senastedatum DESC;
END
Conny Westh är inte uppkopplad   Svara med citatSvara med citat
Oläst 2013-01-31, 23:19 #7
Conny Westh Conny Westh är inte uppkopplad
Klarade millennium-buggen
 
Reg.datum: Aug 2005
Inlägg: 5 166
Conny Westh Conny Westh är inte uppkopplad
Klarade millennium-buggen
 
Reg.datum: Aug 2005
Inlägg: 5 166
Kod:
-- --------------------------------------------------------------------------------
-- Routine DDL
-- Note: comments before and after the routine body will not be stored by the server
-- --------------------------------------------------------------------------------
DELIMITER $$

CREATE DEFINER=`root`@`localhost` PROCEDURE `ThreadsByLatestActiveDate`()
BEGIN
	SELECT threadid, MAX(LatestActiveDate) as LatestActiveDate
	FROM
	(
		SELECT threadid, MAX(createddate) AS LatestActiveDate from wn.threads
		GROUP BY threadid
		UNION 
		SELECT threadid, MAX(created)  AS LatestActiveDate from wn.posts
		GROUP BY threadid
	) x
	GROUP BY threadid
	ORDER BY LatestActiveDate DESC;
END

Jag döpte om proceduren och fixade lite testkod i PHP om någon vill provköra proceduren i PHP.

Kod:
<?php

$host="localhost";
$port=3306;
$socket="";
$user="root";
$password="mypassword";
$dbname="wn";

$con = new mysqli($host, $user, $password, $dbname, $port, $socket)
	or die ('Could not connect to the database server' . mysqli_connect_error());

//$con->close();

$query = "call `wn`.`ThreadsByLatestActiveDate`";

if ($stmt = $con->prepare($query)) 
{
    $stmt->execute();
    $stmt->bind_result($threadId, $latestActiveDate);
    while ($stmt->fetch()) 
	{
        printf("%s, %s\n", $threadId, $latestActiveDate);
    }
    $stmt->close();
}
?>
Conny Westh är inte uppkopplad   Svara med citatSvara med citat
Oläst 2013-02-01, 06:16 #8
jonny jonny är inte uppkopplad
Supermoderator
 
Reg.datum: Sep 2003
Inlägg: 6 941
jonny jonny är inte uppkopplad
Supermoderator
 
Reg.datum: Sep 2003
Inlägg: 6 941
Jag förstår inte hur det kan finnas trådar utan inlägg. Där ligger nog pudelns kärna.
jonny är inte uppkopplad   Svara med citatSvara med citat
Svara


Aktiva användare som för närvarande tittar på det här ämnet: 1 (0 medlemmar och 1 gäster)
 
Ämnesverktyg
Visningsalternativ

Regler för att posta
Du får inte posta nya ämnen
Du får inte posta svar
Du får inte posta bifogade filer
Du får inte redigera dina inlägg

BB-kod är
Smilies är
[IMG]-kod är
HTML-kod är av

Forumhopp


Alla tider är GMT +2. Klockan är nu 08:44.

Programvara från: vBulletin® Version 3.8.2
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Svensk översättning av: Anders Pettersson
 
Copyright © 2017