Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: optymalny algorytm wyszukiwania
Forum PHP.pl > Forum > Bazy danych > MySQL
leon1313
Z góry przepraszam za mało znaczący tytuł tematu.
Posiadam tabelę w bazie danych w mysql o strukturze:
`id` - int, autoincremental
`name` - varchar
`status` - varchar
`start` - datetime
`stop` - datetime
`opis` - longtext

Przechowywane i dopisywane są w niej nazwy wykonanych zadań wraz z datą startu, stopu, oraz statusie zakończenia + w opisie log.
Wartości dla `name` są powtarzalne, jest to ok 150 różnych wpisów (chociaż zawsze mogą dojść nowe). `status` możne przyjmować tylko 3 wartości- 'O' (o.k) , 'B' (bad), 'U' (unknown).

Problemik polega na wyszukaniu wszystkich zadań, które ostatnio zakończyły się (`stop`) co najmniej 3-krotnym niepowodzeniem (`status` = 'B'), przy czym status 'U' zadania nie jest brany w ogóle pod uwagę.
Raport musi zawierać:
nazwę zadania ( `name`),
ile razy się nie udał ,
ostatni udany (`id`),
ostatni nieudany(`id`)
Proste wyszukiwanie poprzez wyciągnięcie wszystkich możliwych nazw i późniejszą iterację (w PHP ) po wszystkich rekordach o danym `name` jest lekko nieefektywne ze względu na ok 1 mln rekordów w tabeli - codziennie pojawia się ok 5000 nowych.

Typ silnika i indexy mogę dowolnie zmieniać.
erix
A nie prościej przez group by...? Trochę zagmatwałeś - np. nie wiem, w jaki sposób mamy rozróżnić na podstawie podanych przez Ciebie danych, ile razy wystąpiło niepowodzenie?
heaven
Tu masz rozwiązanie

  1. SELECT name, GROUP_CONCAT(STATUS ORDER BY stop DESC SEPARATOR '') AS statusy FROM testowa WHERE STATUS <> 'U' GROUP BY name HAVING LENGTH(statusy)>LENGTH(TRIM(LEADING 'BBB' FROM statusy));
  2.  
  3. +------+------------+
  4. | name | statusy |
  5. +------+------------+
  6. | zda1 | BBBOOOOOBB |
  7. +------+------------+

wysciwetlą Ci sie nazwy i lista statusow jakie mialy pokolei jesli liczba bledow ostatnich wynosi wiecej niz 2 pomijajac status 'U'
jesli chcesz wiecej danych to musisz pokombinować. Np. zeby jeszcze podawal ile ostatnich razy pod rzad sie nie udał (pomijajac 'U')

  1. SELECT *,(LENGTH(statusy)-LENGTH(TRIM(LEADING 'B' FROM statusy))) AS 'ilosc_B' FROM (SELECT name, GROUP_CONCAT(STATUS ORDER BY stop DESC SEPARATOR '') AS statusy FROM testowa WHERE STATUS <> 'U' GROUP BY name HAVING LENGTH(statusy)>LENGTH(TRIM(LEADING 'BBB' FROM statusy))) AS tab;
  2.  
  3. +------+------------+---------+
  4. | name | statusy | ilosc_B |
  5. +------+------------+---------+
  6. | zda1 | BBBOOOOOBB | 3 |
  7. +------+------------+---------+


dodatkowe dane jesli to zapytanie nie zwraca duzo wierszy mozesz pobrac dodatkowymi zapytaniami juz dla konkretnych name pobranych powyzszym zapytaniem
leon1313
Sprawdzę jutro na tabeli i zapodam wynik.
Obecnie algorytm wyszukuje wszystkie unikalne nazwy:
SELCET DISTINCT name FROM tabela ORDER BY name;

a z uzyskanej listy wybierane są rekordy dla konkretnego zadania

SELECT id, status FROM tabela WHERE name='zadanieX' ORDER BY id DESC;

w PHP następuje zliczanie rekordów ze `status`=' B' od najnowszego( największe `id`) aż do tego, który ma `status`= 'O'

Napiszę szczerze, że nie wiem, w jaki sposób wyciągnąć jednym zapytaniem listę zadań, których ostatni `status`='B'.
(nadal muszę uwzględnić to, że `status`='U' w ogóle nie jest brany pod uwagę!!!)
Wtedy byłoby znacznie mniej do przeglądania.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.