2010-09-03 3 views
0

Je fais actuellement un travail d'été et je dois prolonger un programme existant.Pouvez-vous accélérer cette requête?

Mon patron m'a demandé de créer un outil pour nos clients afin qu'ils puissent voir combien coûtent leurs employés, par mois. Mais ce n'est pas tout. Le fait est qu'une entreprise peut avoir une ou plusieurs «sociétés» ou sous-entreprises. Nous voulons savoir combien coûte un employé par société dans une entreprise.

Ce sont la table que j'utilise:

  • société: un subcompany avec un people_id qui contient le nom, etc., de la société
  • feuille de temps: les entrées de feuille de temps qui contiennent des informations de la personne et de la société
  • personnes: toutes les personnes ou contacts dans la base de données
  • salarystate: contient le salaire d'une personne pour un mois spécifique
  • frais généraux: frais généraux pour une personne pour un mois spécifique (Notez que la date est une chaîne (!) formatée comme ceci: AAAA-MM-JJ)

Cette requête fonctionne, mais elle prend beaucoup de temps à s'exécuter. Y a-t-il un moyen de le rendre plus rapide?

Je choisis l'année et le mois, j'obtiens le nom de l'employé (travailleur) et le nom de la société. Ensuite, je sélectionne la somme des minutes que l'employé a travaillé (pour une société spécifique). Et enfin, je calcule le coût en vérifiant son salaire pour ce mois et les frais généraux pour ce mois.

SELECT 
    YEAR(TS.assigndate) AS timesheet_year, 
    MONTH(TS.assigndate) AS timesheet_month, 
    CONCAT(TP.name, ' ', TP.firstname) AS worker, 
    CONCAT(SP.name, ' ', SP.firstname) AS society, 
    (
     SELECT 
      SUM(timeunits) AS minutes 
     FROM timesheet 
     WHERE 
      people_id = TP.id AND 
      society_id = S.id AND 
      MONTH(assigndate) = timesheet_month 
    ) AS minutes, 
    (
     SELECT (minutes/60) 
    ) AS hours, 
    (
     SELECT(OO.hourtarif + SS.hourtarif) AS cost 
     FROM salarystate SS, overhead OO 
     WHERE 
      people_id = TP.id AND 
      YEAR(OO.date) = timesheet_year AND 
      MONTH(OO.date) = timesheet_month AND 
      CONVERT(SUBSTRING(SS.month FROM 1 FOR 4), UNSIGNED) = timesheet_year AND 
      CONVERT(SUBSTRING(SS.month, -2), UNSIGNED) = timesheet_month 
    ) AS cost, 
    (
     SELECT (hours * cost) 
    ) AS total_cost 
FROM timesheet TS, society S, people SP, people TP 
WHERE 
    S.id = TS.society_id AND 
    SP.id = S.people_id AND 
    TP.id = TS.people_id 
GROUP BY timesheet_year, timesheet_month, worker, society; 
+0

Avez-vous des index sur certaines colonnes de table de base de données? – heb

+0

Non, et je ne peux pas en créer. Je n'ai pas conçu la base de données et je ne peux pas l'ajuster non plus ... –

+0

yo peut mettre à jour le serveur de base de données. :-) – Koekiebox

Répondre

1

Maintenant, j'utiliser des tables temporaires, il va vite enfer :). Ceci est le code maintenant, si vous êtes intéressé:

CREATE TEMPORARY TABLE IF NOT EXISTS people_hours (
    people_id INTEGER NOT NULL, 
    society_id INTEGER NOT NULL, 
    year INTEGER NOT NULL, 
    month INTEGER NOT NULL, 
    hours DOUBLE NOT NULL, 
    PRIMARY KEY(people_id, society_id, year, month) 
); 

CREATE TEMPORARY TABLE IF NOT EXISTS people_cost (
    people_id INTEGER NOT NULL, 
    year INTEGER NOT NULL, 
    month INTEGER NOT NULL, 
    cost DOUBLE NOT NULL, 
    PRIMARY KEY(people_id, year, month) 
); 

TRUNCATE people_hours; 
TRUNCATE people_cost; 

INSERT INTO people_hours (people_id, society_id, year, month, hours) 
SELECT 
    p.id as people_id, 
    s.id as society_id, 
    YEAR(t.assigndate) as year, 
    MONTH(t.assigndate) as month, 
    SUM(t.timeunits)/60 as hours 
FROM people p, society s, timesheet t 
WHERE 
    t.society_id = s.id AND 
    t.people_id = p.id 
GROUP BY year, month, people_id, society_id; 

INSERT INTO people_cost (people_id, year, month, cost) 
SELECT 
    p.id as people_id, 
    YEAR(o.date) as cost_year, 
    MONTH(o.date) as cost_month, 
    SUM(o.hourtarif + s.hourtarif) as cost 
FROM people p, salarystate s, overhead o 
WHERE 
    s.people_id = p.id AND 
    CONVERT(SUBSTRING(s.month FROM 1 FOR 4), UNSIGNED) = YEAR(o.date) AND 
    CONVERT(SUBSTRING(s.month, -2), UNSIGNED) = MONTH(o.date) 
GROUP BY cost_year, cost_month, people_id; 

SELECT 
    h.year, 
    h.month, 
    h.society_id, 
    h.hours, 
    c.cost, 
    (h.hours * c.cost) AS total_cost, 
    CONCAT(p.name, ' ', p.firstname) AS employee, 
    CONCAT(ps.name, ' ', ps.firstname) AS society 
FROM people_hours h, people_cost c, people p, people ps, society s 
WHERE 
    h.society_id = s.id AND 
    h.people_id = p.id AND 
    h.people_id = c.people_id AND 
    s.people_id = ps.id AND 
    h.year = c.year AND 
    h.month = c.month 
ORDER BY h.year, h.month, h.people_id, h.society_id; 
+0

Bon de voir que vous avez une solution, le problème avec la requête d'origine est que les calculs de sous-requêtes ont dû être exécutés par ligne car ils font partie de la sélection, si vous étiez dans une situation où vous ne pouviez pas créer de tables temporaires avez réécrit la requête de sorte que vous vous êtes joint à la sous-requête en déplaçant la partie where de votre sous-requête dans la condition 'on' de la jointure – ejrowley