我有一個使用JomSocial的Joomla網站。我有一個.NET網絡應用程序,我正在努力,最終將取代Joomla,因爲我更喜歡.NET over PHP。現在我有.NET用戶正在使用的移動網站。LINQ性能問題
LINQ to Entity使開發非常迅速,但我現在正在嘗試解決性能問題。相互發送消息是#1活動,迄今爲止發送了超過40k條消息。這也是我遇到性能問題的地方。以下是JomSocial用於存儲消息的兩個表格。下面是我正在使用的當前LINQ代碼,它返回我想要的結果,僅需兩秒即可完成。
我認爲通過列名你可能會弄清楚數據是什麼樣子,但如果沒有,我可以創建一些,然後在這裏發佈一些,因爲我必須用盡一點點。我應該提到的是,我正在使用帶有.NET 3.5和MySQL w/MySQL .NET Connector的實體框架。
表:
delimiter $$
CREATE TABLE `jos_community_msg` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`from` int(10) unsigned NOT NULL,
`parent` int(10) unsigned NOT NULL,
`deleted` tinyint(3) unsigned DEFAULT '0',
`from_name` varchar(45) NOT NULL,
`posted_on` datetime DEFAULT NULL,
`subject` tinytext NOT NULL,
`body` text NOT NULL,
PRIMARY KEY (`id`),
KEY `parent` (`parent`),
KEY `deleted` (`deleted`),
KEY `from` (`from`)
) ENGINE=MyISAM AUTO_INCREMENT=340 DEFAULT CHARSET=utf8$$
delimiter $$
CREATE TABLE `jos_community_msg_recepient` (
`msg_id` int(10) unsigned NOT NULL,
`msg_parent` int(10) unsigned NOT NULL DEFAULT '0',
`msg_from` int(10) unsigned NOT NULL,
`to` int(10) unsigned NOT NULL,
`bcc` tinyint(3) unsigned DEFAULT '0',
`is_read` tinyint(3) unsigned DEFAULT '0',
`deleted` tinyint(3) unsigned DEFAULT '0',
UNIQUE KEY `un` (`msg_id`,`to`),
KEY `msg_id` (`msg_id`),
KEY `to` (`to`),
KEY `idx_isread_to_deleted` (`is_read`,`to`,`deleted`),
KEY `from` (`msg_from`),
KEY `parent` (`msg_parent`),
KEY `deleted` (`deleted`),
KEY `to_deleted` (`deleted`,`to`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8$$
LINQ:
var messages = (
from b in context.jos_community_msg
join i in (
from i in context.jos_community_msg_recepient
join a in context.jos_community_msg on i.msg_id equals a.id
where i.to == userId && && a.deleted == 0
group a by a.parent into g
select g.Max(p => p.id)) on b.id equals i
join a in context.jos_community_msg_recepient on i equals a.msg_id
orderby b.id descending
select new MessageHeaderItem()
{
IsDeleted = false,
IsRead = (a.is_read.Value == 0) ? false : true,
MessageId = b.parent,
Sent = b.posted_on.Value,
Subject = b.subject,
UserId = a.msg_from
});
total = messages.Count();
return messages.Skip(start).Take(max).ToList();
我已經嘗試了一堆的變化,但沒有任何已經快成功了。使用子選擇對性能不利,但我不知道如何從該表中獲取消息鏈中的最後一條消息。
更新: 這裏是正在生成的SQL:
SELECT
`Limit1`.`C1`,
`Limit1`.`C2`,
`Limit1`.`C3`,
`Limit1`.`parent`,
`Limit1`.`posted_on`,
`Limit1`.`subject`,
`Limit1`.`msg_from`,
`Limit1`.`C4`,
`Limit1`.`C5`,
`Limit1`.`C6`
FROM (SELECT
`Extent1`.`id`,
`Extent1`.`parent`,
`Extent1`.`posted_on`,
`Extent1`.`subject`,
`Extent6`.`msg_from`,
1 AS `C1`,
cast(0 as decimal(0,0)) AS `C2`,
CASE WHEN (0 = (`Extent6`.`is_read`)) THEN (cast(0 as decimal(0,0))) ELSE (cast(1 as decimal(0,0))) END AS `C3`,
'Test' AS `C4`,
'' AS `C5`,
'' AS `C6`
FROM `jos_community_msg` AS `Extent1` INNER JOIN (SELECT
(SELECT
Max(`Extent5`.`id`) AS `A1`
FROM (SELECT
`jos_community_msg_recepient`.`bcc`,
`jos_community_msg_recepient`.`deleted`,
`jos_community_msg_recepient`.`is_read`,
`jos_community_msg_recepient`.`msg_from`,
`jos_community_msg_recepient`.`msg_id`,
`jos_community_msg_recepient`.`msg_parent`,
`jos_community_msg_recepient`.`to`
FROM `jos_community_msg_recepient` AS `jos_community_msg_recepient`) AS `Extent4` INNER JOIN `jos_community_msg` AS `Extent5` ON (`Extent4`.`msg_id` = `Extent5`.`id`) OR ((`Extent4`.`msg_id` IS NULL) AND (`Extent5`.`id` IS NULL))
WHERE ((`Extent4`.`to` = 62) AND (0 = (`Extent5`.`deleted`))) AND ((`Extent5`.`parent` = `Project2`.`parent`) OR ((`Extent5`.`parent` IS NULL) AND (`Project2`.`parent` IS NULL)))) AS `C1`
FROM (SELECT
62 AS `p__linq__5`,
`Distinct1`.`parent`
FROM (SELECT DISTINCT
`Extent3`.`parent`
FROM (SELECT
`jos_community_msg_recepient`.`bcc`,
`jos_community_msg_recepient`.`deleted`,
`jos_community_msg_recepient`.`is_read`,
`jos_community_msg_recepient`.`msg_from`,
`jos_community_msg_recepient`.`msg_id`,
`jos_community_msg_recepient`.`msg_parent`,
`jos_community_msg_recepient`.`to`
FROM `jos_community_msg_recepient` AS `jos_community_msg_recepient`) AS `Extent2` INNER JOIN `jos_community_msg` AS `Extent3` ON (`Extent2`.`msg_id` = `Extent3`.`id`) OR ((`Extent2`.`msg_id` IS NULL) AND (`Extent3`.`id` IS NULL))
WHERE (`Extent2`.`to` = 62) AND (0 = (`Extent3`.`deleted`))) AS `Distinct1`) AS `Project2`) AS `Project3` ON (`Extent1`.`id` = `Project3`.`C1`) OR ((`Extent1`.`id` IS NULL) AND (`Project3`.`C1` IS NULL)) INNER JOIN (SELECT
`jos_community_msg_recepient`.`bcc`,
`jos_community_msg_recepient`.`deleted`,
`jos_community_msg_recepient`.`is_read`,
`jos_community_msg_recepient`.`msg_from`,
`jos_community_msg_recepient`.`msg_id`,
`jos_community_msg_recepient`.`msg_parent`,
`jos_community_msg_recepient`.`to`
FROM `jos_community_msg_recepient` AS `jos_community_msg_recepient`) AS `Extent6` ON (`Project3`.`C1` = `Extent6`.`msg_id`) OR ((`Project3`.`C1` IS NULL) AND (`Extent6`.`msg_id` IS NULL))
ORDER BY
`id` DESC LIMIT 0,16) AS `Limit1`;
下面是從MySQL的解釋:
1 PRIMARY <derived2> ALL 16
2 DERIVED <derived3> ALL 55 Using temporary; Using filesort
2 DERIVED Extent1 eq_ref PRIMARY PRIMARY 4 Project3.C1 1 Using where
2 DERIVED <derived9> ALL 333 Using where; Using join buffer
9 DERIVED jos_community_msg_recepient ALL 333
3 DERIVED <derived6> ALL 55
6 DERIVED <derived7> ALL 55
7 DERIVED <derived8> ALL 333 Using where; Using temporary
7 DERIVED Extent3 eq_ref PRIMARY,deleted PRIMARY 4 Extent2.msg_id 1 Using where; Distinct
8 DERIVED jos_community_msg_recepient ALL 333
4 DEPENDENT SUBQUERY Extent5 ref PRIMARY,parent,deleted parent 4 Project2.parent 2 Using where
4 DEPENDENT SUBQUERY <derived5> ALL 333 Using where; Using join buffer
5 DERIVED jos_community_msg_recepient ALL 333
這實際上是與MySQL。我將使用慢查詢日誌中的計數部分更新我的帖子。也許我需要在LINQ中改變一些東西。 – GregInWI2 2010-09-20 16:25:09
對不起。雖然您當然不能使用Microsoft工具,但我的建議仍然存在。找出執行確切的查詢並查看問題出在哪裏。你將不得不分析這個。也有用於MySql的工具。 – Steven 2010-09-20 16:31:33
對,我明白這一點。這些信息現在可以在這裏找到。我很想知道我可以在LINQ中更改哪些內容,以便生成更好的查詢。如果什麼都不能改變,那麼我想我必須使用動態SQL或過程。 – GregInWI2 2010-09-20 16:39:37