1
作爲我現在項目的一部分,我恢復了提供一組在線報告的任務。Django的性能 - 是SQL視圖不夠好?
根據報告的複雜性和最佳性能,我決定在Posgres上編寫sql視圖,然後將它們附加到只讀的Django模型。
我想問你你對這種方法的看法,因爲我的一些團隊成員說我應該只使用ORM,在這種情況下我認爲這不是最好的。
讓我知道你的想法B/C我真正需要的論點,但不喜歡:「這是錯誤的做法B/C我認爲這是它是什麼 」 謝謝,
Ĵ
例如SQL視圖:這是隻讀這裏
DROP VIEW IF EXISTS riss_all_alerts;
DROP VIEW IF EXISTS riss_state_alerts;
DROP VIEW IF EXISTS riss_zone_alerts;
DROP VIEW IF EXISTS riss_lga_alerts;
-- ZONE PART
CREATE VIEW riss_zone_alerts AS
WITH rissAlertPart AS (
SELECT
zone_name AS alert_zone,
min(rissAlert) AS alert,
month
FROM (
SELECT
date_part('month', odk_submission_date) AS month,
zone_name,
CASE
WHEN (reason_no = 'N/A' AND reason_yes = 'N/A' AND ss_to_del = 1)
THEN '1'
WHEN (reason_yes <> 'N/A' OR ss_to_del = 0)
THEN '3'
WHEN (reason_no <> 'N/A' OR ss_to_del = 2)
THEN '2'
ELSE 'ghj'
END AS rissAlert
FROM riss_rissdetail
WHERE alert_id = 'zn-ssn'
GROUP BY zone_name, reason_no, reason_yes, ss_to_del, date_part('month', odk_submission_date)
) AS a
GROUP BY a.zone_name, month
ORDER BY 1, 2
)
SELECT
'zn-ssn'::TEXT AS alert_id,
zone_name AS level_name,
CASE WHEN greenCount :: FLOAT > 0
THEN greenCount :: FLOAT
ELSE 0 END/count(*) AS value,
to_char(CASE WHEN greenCount :: FLOAT > 0
THEN greenCount :: FLOAT
ELSE 0 END, 'FM999MI') || '/' || to_char(count(*), 'FM999MI') AS extra_desc,
alert AS alert_level,
date_part('month', odk_submission_date) :: INT AS alert_date
FROM riss_rissdetail
LEFT JOIN (
SELECT
date_part('month', odk_submission_date) AS green_month,
zone_name AS green_zone,
count(*) AS greenCount
FROM riss_rissdetail
WHERE alert_id = 'zn-ssn' AND ss_to_del = 0
GROUP BY zone_name, date_part('month', odk_submission_date)
) AS g ON g.green_zone = zone_name AND g.green_month = date_part('month', odk_submission_date)
LEFT JOIN rissAlertPart AS r
ON r.alert_zone = zone_name AND r.month = date_part('month', odk_submission_date)
WHERE alert_id = 'zn-ssn'
GROUP BY zone_name, g.green_zone, greenCount, alert, date_part('month', odk_submission_date);
--LGA PART
CREATE VIEW riss_lga_alerts AS
WITH rissAlertPart AS (
SELECT
lga_name AS alert_lga,
min(rissAlert) AS alert,
month
FROM (
SELECT
date_part('month', odk_submission_date) AS month,
lga_name,
CASE
WHEN (reason_no = 'N/A' AND reason_yes = 'N/A' AND ss_to_del = 1)
THEN '1'
WHEN (reason_yes <> 'N/A' OR ss_to_del = 0)
THEN '3'
WHEN (reason_no <> 'N/A' OR ss_to_del = 2)
THEN '2'
ELSE 'ghj'
END AS rissAlert
FROM riss_rissdetail
WHERE alert_id = 'lg-ssn'
GROUP BY lga_name, reason_no, reason_yes, ss_to_del, date_part('month', odk_submission_date)
) AS a
GROUP BY a.lga_name, month
ORDER BY 1, 2
)
SELECT
'lg-ssn'::TEXT AS alert_id,
lga_name AS level_name,
CASE WHEN greenCount :: FLOAT > 0
THEN greenCount :: FLOAT
ELSE 0 END/count(*) AS value,
to_char(CASE WHEN greenCount :: FLOAT > 0
THEN greenCount :: FLOAT
ELSE 0 END, 'FM999MI') || '/' || to_char(count(*), 'FM999MI') AS extra_desc,
alert AS alert_level,
date_part('month', odk_submission_date) :: INT AS alert_date
FROM riss_rissdetail
LEFT JOIN (
SELECT
date_part('month', odk_submission_date) AS green_month,
lga_name AS green_lga,
count(*) AS greenCount
FROM riss_rissdetail
WHERE alert_id = 'lg-ssn' AND ss_to_del = 0
GROUP BY lga_name, date_part('month', odk_submission_date)
) AS g ON g.green_lga = lga_name AND g.green_month = date_part('month', odk_submission_date)
LEFT JOIN rissAlertPart AS r
ON r.alert_lga = lga_name AND r.month = date_part('month', odk_submission_date)
WHERE alert_id = 'lg-ssn'
GROUP BY lga_name, g.green_lga, greenCount, alert, date_part('month', odk_submission_date);
--STATE PART
CREATE VIEW riss_state_alerts AS
WITH rissAlertPart AS (
SELECT
state_name AS alert_state,
min(rissAlert) AS alert,
month
FROM (
SELECT
date_part('month', odk_submission_date) AS month,
state_name,
CASE
WHEN (reason_no = 'N/A' AND reason_yes = 'N/A' AND ss_to_del = 1)
THEN '1'
WHEN (reason_yes <> 'N/A' OR ss_to_del = 0)
THEN '3'
WHEN (reason_no <> 'N/A' OR ss_to_del = 2)
THEN '2'
ELSE 'ghj'
END AS rissAlert
FROM riss_rissdetail
WHERE alert_id = 'st-ssn'
GROUP BY state_name, reason_no, reason_yes, ss_to_del, date_part('month', odk_submission_date)
) AS a
GROUP BY a.state_name, month
ORDER BY 1, 2
)
SELECT
'st-ssn'::TEXT AS alert_id,
state_name AS level_name,
CASE WHEN greenCount :: FLOAT > 0
THEN greenCount :: FLOAT
ELSE 0 END/count(*) AS value,
to_char(CASE WHEN greenCount :: FLOAT > 0
THEN greenCount :: FLOAT
ELSE 0 END, 'FM999MI') || '/' || to_char(count(*), 'FM999MI') AS extra_desc,
alert AS alert_level,
date_part('month', odk_submission_date) :: INT AS alert_date
FROM riss_rissdetail
LEFT JOIN (
SELECT
date_part('month', odk_submission_date) AS green_month,
state_name AS green_state,
count(*) AS greenCount
FROM riss_rissdetail
WHERE alert_id = 'st-ssn' AND ss_to_del = 0
GROUP BY state_name, date_part('month', odk_submission_date)
) AS g ON g.green_state = state_name AND g.green_month = date_part('month', odk_submission_date)
LEFT JOIN rissAlertPart AS r
ON r.alert_state = state_name AND r.month = date_part('month', odk_submission_date)
WHERE alert_id = 'st-ssn'
GROUP BY state_name, g.green_state, greenCount, alert, date_part('month', odk_submission_date);
CREATE VIEW riss_all_alerts AS
SELECT *
FROM riss_zone_alerts
UNION ALL
SELECT *
FROM riss_lga_alerts
UNION ALL
SELECT *
FROM riss_state_alerts;
我的Django模型:
class RissAlertView(models.Model):
alert_id = models.CharField(max_length=255, primary_key=True)
value = models.FloatField()
alert_date = models.PositiveSmallIntegerField(null=True)
alert_level = models.PositiveSmallIntegerField(null=True)
level_name = models.CharField(max_length=255, null=True)
extra_desc = models.CharField(max_length=255, null=True)
class Meta:
db_table = u'riss_all_alerts'
managed = False
verbose_name = "Riss Alerts View"
verbose_name_plural = "Riss Alerts View"
permissions = (("can_access_riss_alerts", "Can access RISS alerts"),)
def __unicode__(self):
return u'%s %s %s' % (self.alert_id, self.levelname, self.alert_date)
def _percenatge_value(self):
"""Returns the percenateg value."""
return self.value * 100
percent = property(_percenatge_value)