sql >> Databáze >  >> RDS >> Mysql

Velmi specifický MySQL dotaz, který chci zlepšit

Pokud máte index s created jako úvodní sloupec může být MySQL schopno provést zpětné skenování. Pokud máte 24hodinové období, které neobsahuje žádné události, můžete vracet řádek, který NENÍ z tohoto období. Abyste se ujistili, že v tomto období zaznamenáváte řádek, musíte do created zahrnout spodní hranici také něco jako toto:

SELECT * FROM `eventos`
 WHERE ... 
   AND `created` <  FROM_UNIXTIME( {$timestamp} )
   AND `created` >= DATE_ADD(FROM_UNIXTIME( {$timestamp} ),INTERVAL -24 HOUR)
 ORDER BY `created` DESC
 LIMIT 1

Myslím, že hlavním klíčem k výkonu je zde index s created jako úvodní sloupec spolu se všemi (nebo většinou) ostatními sloupci, na které odkazuje klauzule WHERE, a ujistěte se, že váš dotaz používá index.

Pokud potřebujete jiný časový interval, až na druhý, lze tento přístup snadno zobecnit.

SELECT * FROM `eventos`
 WHERE ... 
   AND `created` <  DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL  0*{$nsecs} SECOND)
   AND `created` >= DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -1*{$nsecs} SECOND)
 ORDER BY `created` DESC
 LIMIT 1

Z vašeho kódu to vypadá, že 24hodinové periody jsou ohraničeny v libovolném čase... pokud funkce času vrací např. 1341580800 ('2012-07-06 13:20'), pak všech deset menstruací bude od 13:20 daného dne do 13:20 následujícího dne.

(POZNÁMKA:ujistěte se, že pokud je vaším parametrem celé číslo unixového časového razítka, že jej databáze interpretuje správně.)

Mohlo by být efektivnější stáhnout deset řádků v jednom dotazu. Pokud existuje záruka, že 'časové razítko' je jedinečné, je možné takový dotaz vytvořit, ale text dotazu bude podstatně složitější než ten, který máte nyní. Mohli bychom se pohrát se získáním MAX (timestamp_) v každém období a pak to spojit, abychom dostali řádek... ale to bude opravdu komplikované.

Pokud bych se chtěl pokusit vytáhnout všech deset řádků, pravděpodobně bych zkusil použít UNION ALL přístup, ne moc hezký, ale aspoň by se to dalo vyladit.

SELECT p0.*
  FROM ( SELECT * FROM `eventos` WHERE ... 
            AND `created` <  DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL  0*24 HOUR)
            AND `created` >= DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -1*24 HOUR)
          ORDER BY `created` DESC LIMIT 1
       ) p0 
 UNION ALL           
SELECT p1.*
  FROM ( SELECT * FROM `eventos` WHERE ... 
            AND `created` <  DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -1*24 HOUR)
            AND `created` >= DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -2*24 HOUR)
          ORDER BY `created` DESC LIMIT 1
       ) p1 
 UNION ALL           
SELECT p2.*
  FROM ( SELECT * FROM `eventos` WHERE ... 
            AND `created` <  DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -2*24 HOUR)
            AND `created` >= DATE_ADD(FROM_UNIXTIME({$timestamp}),INTERVAL -3*24 HOUR)
          ORDER BY `created` DESC LIMIT 1
       ) p2 
 UNION ALL           
SELECT p3.*
  FROM ...

Opět by se to dalo zobecnit a přejít jako argument během několika sekund. Nahraďte HOUR za SECOND a nahraďte '24' parametrem vazby, který má počet sekund.

Je to dost táhlé, ale mělo by to běžet v pořádku.

Dalším opravdu chaotickým a komplikovaným způsobem, jak to získat zpět v jedné sadě výsledků, by bylo použít inline zobrazení k získání koncového časového razítka pro deset období, něco takového:

     SELECT p.period_end
       FROM (SELECT DATE_ADD(t.t_,INTERVAL -1 * i.i_* {$nsecs} SECOND) AS period_end
               FROM (SELECT FROM_UNIXTIME( {$timestamp} ) AS t_) t
               JOIN (SELECT 0 AS i_
                     UNION ALL SELECT 1
                     UNION ALL SELECT 2
                     UNION ALL SELECT 3
                     UNION ALL SELECT 4
                     UNION ALL SELECT 5
                     UNION ALL SELECT 6
                     UNION ALL SELECT 7
                     UNION ALL SELECT 8
                     UNION ALL SELECT 9
                    ) i
            ) p

A pak to připojte ke svému stolu ...

  ON `created` < p.period_end
 AND `created` >= DATE_ADD(p.period_end,INTERVAL -1 * {$nsecs} SECOND)

A stáhnout MAX (vytvořeno) pro každé období GROUP BY p.period_end, zabalit to do vloženého zobrazení.

A pak to připojte zpět ke svému stolu, abyste získali každý řádek.

Ale to je opravdu, opravdu chaotické, těžko pochopitelné a pravděpodobně to nebude rychlejší (nebo efektivnější) než to, co již děláte. Největším zlepšením, které byste mohli udělat, je čas potřebný ke spuštění 9 vašich dotazů.



  1. Proč došlo k selhání databáze MySQL? Získejte přehled s novým rámcem MySQL Freeze Frame

  2. Chyba:Při instalaci psycopg2 na Alpine v Dockeru nebyl nalezen spustitelný soubor pg_config

  3. MySQL Trigger - smazat po aktualizaci

  4. Chyba při protokolování mysql, osvědčený postup