Mysql
 sql >> база данни >  >> RDS >> Mysql

Много специфична MySQL заявка, която искам да подобря

Ако имате индекс с created като водеща колона, MySQL може да е в състояние да направи обратно сканиране. Ако имате 24-часов период, който няма събития, може да връщате ред, който НЕ е от този период. За да сте сигурни, че получавате ред през този период, наистина ще трябва да включите долна граница на created колона също, нещо подобно:

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

Мисля, че големият ключ към производителността тук е индекс с created като водеща колона, заедно с всички (или повечето) други колони, посочени в клаузата WHERE, и се уверете, че индексът се използва от вашата заявка.

Ако имате нужда от различен интервал от време, до втория, този подход може лесно да бъде обобщен.

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

От вашия код изглежда, че 24-часовите периоди са ограничени в произволно време... ако функцията за време връща напр. 1341580800 ('2012-07-06 13:20'), тогава всичките ви десет цикъла ще бъдат от 13:20 на даден ден до 13:20 на следващия ден.

(ЗАБЕЛЕЖКА:уверете се, че ако параметърът ви е цяло число с времеви клеймо на unix, това се интерпретира правилно от базата данни.)

Може да е по-ефективно да издърпате десетте реда в една заявка. Ако има гаранция, че 'timestamp' е уникален, тогава е възможно да се създаде такава заявка, но текстът на заявката ще бъде значително по-сложен от този, който имате сега. Можем да се забъркаме с получаването на MAX(timestamp_) в рамките на всеки период и след това да го присъединим обратно, за да получим реда... но това ще бъде наистина объркано.

Ако щях да се опитам да изтегля всичките десет реда, вероятно щях да опитам да използвам UNION ALL подход, не е много красив, но поне може да бъде настроен.

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 ...

Отново, това може да бъде обобщено, за да премине за няколко секунди като аргумент. Заменете HOUR със SECOND и заменете „24“ с параметър за свързване, който има брой секунди.

Това е доста дълго, но трябва да работи добре.

Друг наистина разхвърлян и сложен начин да върнете това обратно в един набор от резултати би бил да използвате вграден изглед, за да получите крайната дата за време за десетте периода, нещо подобно:

     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

И след това присъединете това към вашата маса ...

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

И издърпайте MAX(създадено) за всеки период GROUP BY p.period_end, увийте това във вграден изглед.

И след това присъединете това обратно към вашата таблица, за да получите всеки ред.

Но това е наистина, наистина объркано, трудно за разбиране и едва ли ще бъде по-бързо (или по-ефективно) от това, което вече правите. Най-голямото подобрение, което бихте могли да направите, е времето, необходимо за изпълнение на 9 от вашите заявки.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. защо тази mysql заявка не работи?

  2. json колона срещу множество колони

  3. Как да разделите резултатите от търсенето по категории? MySQL + PHP

  4. Как мога да вмъкна реално време на събитие в база данни с помощта на php mysqli?

  5. Игнорирайте определени критерии WHERE