The PIT
Röster från ITM-koncernen.

Beräknad väntetid: 5 minuter.

February 3, 2009 13:00 by Stefan Karlsson

 

Implementerade precis “beräknad väntetid” i vårt köhanteringssystem, ni vet ett sådant där kunden trycker fram ett könummer och sedan väntar på att just det numret ska visas upp på en display så man vet vilken kassa man ska gå till. 

Det förvånade mig att det fanns så många sätt att beräkna just denna väntetid på, många uppenbarligen felaktiga också.

För tydlighetsskull så benämner jag det nummer som kunden får fram på sitt kvitto för TicketNumber och det nummer som kassören matar fram för QueNumber. QueNumber är alltså det nummer som just nu ska betjänas, det kan aldrig vara större än NextTicketNumber (Sista utskrivna TicketNumber+1).

Skillnaden i värde mellan QueNumber och NextTicketNumber är alltså detsamma som antalet kunder som står och väntar på att bli betjänade.

Variant 1

Min första approach var att varje gång en kassör matar fram ett QueNumber i kassan så sparas kassaid, quenumber och en timestamp i en tabell och därefter så är det lätt att få fram hur lång tid det tog mellan varje frammatning och på så sätt få fram en “velocity”, antal frammatningar per timme. Om man räknar fram att man har 10 frammatningar per timme och sedan tar NextTicketNumber-QueNumber (för att få fram antal väntande kunder) så kan man med den informationen räkna ut hur lång genomsnittlig väntetid det blir för de väntande kunderna. För att minska eventuella avvikelser när busslaster kommer så kan man öka tiden man beräknar på till två timmar.

En stored procedure tog snabbt fram detta:

CREATE PROCEDURE GetQueWaitTime AS 
declare @NextTicketNumber int
select @NextTicketNumber=countervalue from skibarcounters where countername='nextticketnumber'
declare @NextQueNumber int
select @NextQueNumber=countervalue from skibarcounters where countername='NextQueNumber'
declare @TicksPerTwoHours int
select @TicksPerTwoHours=count(*) from questamps where datediff(n,stamp,getdate())<120
select 120/@TicksPerTwoHours   * (@NextTicketNumber-@NextQueNumber)

 

Uppenbara nackdelar med denna metoden:

  • Om man inte haft kunder på två timmar, eller väldigt få, så blir antal frammatningar per två timmar 0 eller nära 0, vilket gör att man får en falsk väntetid. Dvs, har man bara haft två kunder så kan det bli så att systemet antar att väntetiden är 30 minuter per kund och kommer det sedan in 10 kunder så kommer systemet visa helt felaktiga väntetider mot verkligheten.
  • Början av dagen när man inte haft några kunder så kommer det inte att finnas tillgängliga data och problemet som uppstår i punkt 1 kommer att uppstå här också.
  • Har man haft kunder och man får fram en genomsnittlig tid på 5 minuters väntetid och sedan har en dödperiod så kommer de där 5 minutrarna att öka hela tiden tills man börjar mata fram nya nummer. Det är inte verklighetsbaserat att väntetiden per kund ska öka bara för att man inte råkar ha några kunder att betjäna.

      Variant 2

      Vi insåg att vi var tvugna att spara ner tidpunkten för när kunden trycker fram sitt nummer, vi modellerade om tabellen lite så att när kunden trycker fram ett TicketNumber så lagras numret och tidpunkt för utskrift och när kassan trycker fram ett QueNumber så uppdateras den raden med kassaid och tidpunkt för betjäning samt en uträknad diff i minuter mellan dessa två tidpunkter. (Genom att matcha mot kvitton skapade i kassan kan man därefter också få fram hur lång tid det tog att betjäna kunden, men det är en annan sak)

      Nu räckte det alltså med en enkel fråga för att få fram genomsnittlig tid, vi nöjer oss med att kolla genomsnittlig faktisk väntetid den senaste timmen, fältet WaitedTime är det uträknade antal minuter kunden fick vänta mellan han tryckte ut sitt könummer och tills könumret visades i displayen, vi kollar bara rader som har ett cashierid som skiljer sig från 0 för det är bara de som blivit “frammatade”:

      select avg(waitedtime) as waitminutes from questamps where

      cashierid<>0 and datediff(n,stamp,getdate())<60

       

      Jag kände mig ganska nöjd med den här lösningen först men sen när jag sovit en natt så kom jag på att denna variant inte tar hänsyn till hur många kunder som står och väntar just nu. Den gör bara halva arbetet, den säger att Senaste timmen var den genomsnittliga väntetiden 5 minuter. Men om det kommit in en ny busslass med personer så att det står 40 personer och väntar så applicerar den inte kunskapen på detta.

      Lösningen är så klart att plocka fram antalet väntande kunder och applicera den genomsnittliga väntetiden på dessa och visa ett modifierat tal för detta.

      Med den modifikationen känns det som att vi har en pålitlig uträkning för att få fram en genomsnittlig väntetid som både tar hänsyn till historik och nuvarande kösituation.

      Det jag skulle vilja lägga till för att förbättra rutinen är att man först filtrerar bort stora avvikelser, t.ex. tar bort de som avviker i tid med mer än x% från genomsnittstiden osv. För att det inte påverkar allt för mycket när 4 busslaster med danskar stormar in. Men det kan man finetune efter att man fått in lite mer verkliga data att titta på.

      Utmaning

      Har du något bättre sätt att få fram en pålitlig siffra eller en helt annan approach (jag har minst 3 varianter till att räkna ut siffran på, mer eller mindre felaktiga eller med falska utslag av väntetider osv) så kommentera gärna artikeln.


    Tags:
    Categories: Programmering | .Net | SQL
    Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed