簡體   English   中英

Doctrine 大規模一對多性能

[英]Doctrine one-to-many performance at scale

我建立了一個新聞提要,其中postpost_reaction具有一對多關系。 這個概念很簡單,一個帖子可以被點贊,每個點贊都存儲在post_reaction表中,連同點贊的人和反應類型(點贊、愛等)

一切正常™,但是隨着規模的擴大,性能會下降,即隨着post_reaction表的增長。

出於測試目的,我生成了 200 個帖子並給每個帖子 1,000 個反應。 這導致post_reaction表中存儲了 200,000 個總反應。

我的 Twig 模板提供了一個帖子列表,限制為 20 個。當模板循環顯示每個帖子時,它會調用post.reactions|length來計算反應的數量。 這將執行以下數據庫查詢:

SELECT
  t0.reaction AS reaction_1,
  t0.id AS id_2,
  t0.created AS created_3,
  t0.post_id AS post_id_4,
  t0.user AS user_5
FROM
  post_reaction t0
WHERE
  t0.post_id = ?

每次運行我正在呈現的 20 個帖子時,此查詢平均需要 4-7 毫秒才能運行。 這總計約 100 毫秒的數據庫查詢只是為了計算帖子。

這看起來還不錯,但是我們觀察到在應用程序中處理這么多數據會產生一些開銷。

查看整個請求的分析器,我們看到以下內容: 頁面性能配置文件 我們在此請求中的整體處理時間為585 毫秒

components/news_post.html.twig是調用觸發數據庫查詢的post.reactions|length的組件。 如果我們在沒有查詢反應的情況下發起相同的請求,我們會觀察到以下情況。 頁面性能配置文件 - 無需查詢反應 我們在此請求中的整體處理時間為179 毫秒

快 406 毫秒/69.4% 我相信這主要歸因於 doctrine 中的開銷,因為它將 20,000 行處理成對象,只是為了我們稍后計算它們。

為了緩解這種情況,我想看看將反應加入到我的帖子查詢中是否會有所幫助。

SELECT
  p0_.replies_allowed AS replies_allowed_0,
  p0_.highlight_date AS highlight_date_1,
  p0_.title AS title_2,
  p0_.content AS content_3,
  p0_.id AS id_4,
  p0_.created AS created_5,
  p0_.updated AS updated_6,
  p0_.news_feed_id AS news_feed_id_7,
  p0_.created_by_id AS created_by_id_8,
  p0_.updated_by_id AS updated_by_id_9
FROM
  post p0_
  INNER JOIN post_reaction p1_ ON (p1_.post_id = p0_.id)
WHERE
  p0_.news_feed_id = ?
ORDER BY
  CASE WHEN p0_.highlight_date > ? THEN 0 ELSE 1 END ASC,
  p0_.created DESC
LIMIT
  20

但是,它會導致查詢中的LIMIT 20子句出現問題,因為由於此數據集中的反應數量,加入反應只允許返回一個帖子。

我不確定我是否應該繼續開發一種使加入成為可能的方法,或者探索一個替代方案,無論是什么。 理想情況下,我想減少 406 毫秒的額外執行時間,因為它幾乎占總頁面處理時間的 70%,只是為了計算喜歡……


編輯:根據要求,output 用於show create table post_reaction

CREATE TABLE `post_reaction` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `post_id` int(11) DEFAULT NULL,
  `user` int(11) DEFAULT NULL,
  `reaction` int(11) NOT NULL,
  `reaction_timestamp` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `IDX_1B3A8E564B89032C` (`post_id`),
  KEY `IDX_1B3A8E568D93D649` (`user`),
  CONSTRAINT `FK_1B3A8E564B89032C` FOREIGN KEY (`post_id`) REFERENCES `post` (`id`),
  CONSTRAINT `FK_1B3A8E568D93D649` FOREIGN KEY (`user`) REFERENCES `user` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=200786 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
  • (第二個查詢)不要JOIN post_reaction ,因為您沒有使用它的任何列。

  • ORDER BY的復雜性使得不可能更快地查看所有 1000 個反應。 因此LIMIT對性能的影響很小。

  • 請提供SHOW CREATE TABLE post_reaction ,我們可以在那里做一些改進。 但是您當然需要一些以post_id開頭的索引。 我們可能會通過重新排列PRIMARY KEY以從該列開始來獲得一些改進。

  • (我對Controller和樹枝一無所知。它們似乎是昂貴的部分?)

更多的

“計算 [每個帖子] 的反應數量”——這是一個不會花費很長時間的 SQL 查詢:

SELECT post_id,
       COUNT(*) AS reaction_count
    FROM post_reaction
    GROUP BY post_id;

無需遍歷帖子; 一次不超過 20 個; 一次簡單地傳遞該表中的索引即可完成所有操作。

我在 92 個國家/地區的 50 萬個城市的表上嘗試了一個等效查詢。 耗時0.13秒。

這里的教訓是,當要求 SQL 在很多行上做很多相同的事情時,它會發光。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM