2016-04-05 32 views
3

我們在MVC 5應用程序中支持MSSQL和MySQL for Entityframework 6。現在,我遇到的問題是使用MySQL連接器和LINQ時,具有INNER JOIN和ORDER BY的查詢將導致查詢進入子選擇,並且ORDER BY在外部應用。這會對性能產生重大影響。這在使用MSSQL連接器時不會發生。這裏是一個例子:MySQL實體框架將查詢包裝爲子選擇順序

SELECT 
    `Project3`.* 
FROM 
    (SELECT 
     `Extent1`.*, 
      `Extent2`.`Name_First` 
    FROM 
     `ResultRecord` AS `Extent1` 
    LEFT OUTER JOIN `ResultInputEntity` AS `Extent2` ON `Extent1`.`Id` = `Extent2`.`Id` 
    WHERE 
     `Extent1`.`DateCreated` <= '4/4/2016 6:29:59 PM' 
      AND `Extent1`.`DateCreated` >= '12/31/2015 6:30:00 PM' 
      AND 0000 = `Extent1`.`CustomerId` 
      AND (`Extent1`.`InUseById` IS NULL OR 0000 = `Extent1`.`InUseById` OR `Extent1`.`LockExpiration` < '4/4/2016 6:29:59 PM') 
      AND `Extent1`.`DivisionId` IN (0000) 
      AND `Extent1`.`IsDeleted` != 1 
      AND EXISTS(SELECT 
       1 AS `C1` 
      FROM 
       `ResultInputEntityIdentification` AS `Extent3` 
      WHERE 
       `Extent1`.`Id` = `Extent3`.`InputEntity_Id` 
        AND 0 = `Extent3`.`Type` 
        AND '0000' = `Extent3`.`Number` 
        AND NOT (`Extent3`.`Number` IS NULL) 
        OR LENGTH(`Extent3`.`Number`) = 0) 
      AND EXISTS(SELECT 
       1 AS `C1` 
      FROM 
       `ResultRecordAssignment` AS `Extent4` 
      WHERE 
       1 = `Extent4`.`AssignmentType` 
        AND `Extent4`.`AssignmentId` = 0000 
        OR 2 = `Extent4`.`AssignmentType` 
        AND `Extent4`.`AssignmentId` = 0000 
        AND `Extent4`.`ResultRecordId` = `Extent1`.`Id`)) AS `Project3` 
ORDER BY `Project3`.`DateCreated` ASC , `Project3`.`Name_First` ASC , `Project3`.`Id` ASC 
LIMIT 0 , 25 

這個查詢簡單地超過幾百萬行時運行。這是上述查詢的解釋:

| id | select_type  | table | type | possible_keys                                      | key      | key_len | ref  | rows  | extra          | 
    | 1 | PRIMARY   | Extent1 | ref | IX_ResultRecord_CustomerId,IX_ResultRecord_DateCreated,IX_ResultRecord_IsDeleted,IX_ResultRecord_InUseById,IX_ResultRecord_LockExpiration,IX_ResultRecord_DivisionId | IX_ResultRecord_CustomerId | 4  | const  | 1  | Using where; Using temporary; Using filesort | 
    | 1 | PRIMARY   | Extent2 | ref | PRIMARY                                        | PRIMARY     | 8  | Extent1.Id | 1  |            | 
    | 4 | DEPENDENT SUBQUERY | Extent4 | ref | IX_RA_AT,IX_RA_A_ID,IX_RA_RR_ID                                  | IX_RA_A_ID     | 5  | const  | 1  | Using where         | 
    | 3 | DEPENDENT SUBQUERY | Extent3 | ALL | IX_InputEntity_Id,IX_InputEntityIdentification_Type,IX_InputEntityIdentification_Number                    |       |   |   | 14341877 | Using where 

現在,因爲它會在MSSQL獲取生成,或者我們根本擺脫子選擇要由秩序,改善是顯着的!

SELECT 
    `Extent1`.*, 
    `Extent2`.`Name_First` 
FROM 
    `ResultRecord` AS `Extent1` 
    LEFT OUTER JOIN `ResultInputEntity` AS `Extent2` ON `Extent1`.`Id` = `Extent2`.`Id` 
WHERE 
    `Extent1`.`DateCreated` <= '4/4/2016 6:29:59 PM' 
     AND `Extent1`.`DateCreated` >= '12/31/2015 6:30:00 PM' 
     AND 0000 = `Extent1`.`CustomerId` 
     AND (`Extent1`.`InUseById` IS NULL 
     OR 0000 = `Extent1`.`InUseById` 
     OR `Extent1`.`LockExpiration` < '4/4/2016 6:29:59 PM') 
     AND `Extent1`.`DivisionId` IN (0000) 
     AND `Extent1`.`IsDeleted` != 1 
     AND EXISTS(SELECT 
      1 AS `C1` 
     FROM 
      `ResultInputEntityIdentification` AS `Extent3` 
     WHERE 
      `Extent1`.`Id` = `Extent3`.`InputEntity_Id` 
       AND 9 = `Extent3`.`Type` 
       AND '0000' = `Extent3`.`Number` 
       AND NOT (`Extent3`.`Number` IS NULL) 
       OR LENGTH(`Extent3`.`Number`) = 0) 
     AND EXISTS(SELECT 
      1 AS `C1` 
     FROM 
      `ResultRecordAssignment` AS `Extent4` 
     WHERE 
      1 = `Extent4`.`AssignmentType` 
       AND `Extent4`.`AssignmentId` = 0000 
       OR 2 = `Extent4`.`AssignmentType` 
       AND `Extent4`.`AssignmentId` = 0000 
       AND `Extent4`.`ResultRecordId` = `Extent1`.`Id`) 
ORDER BY `Extent1`.`DateCreated` ASC , `Extent2`.`Name_First` ASC , `Extent1`.`Id` ASC 
LIMIT 0 , 25 

此查詢現在在0.10秒內運行!和解釋,現在的計劃是這樣的:

| id | select_type | table  | type | possible_keys                                        | key        | key_len | ref     | rows | extra          | 
| 1 | PRIMARY  | <subquery2> | ALL | distinct_key                                         |         |   |      | 1 | Using temporary; Using filesort    | 
| 1 | PRIMARY  | Extent1  | ref | PRIMARY,IX_ResultRecord_CustomerId,IX_ResultRecord_DateCreated,IX_ResultRecord_IsDeleted,IX_ResultRecord_InUseById,IX_ResultRecord_LockExpiration,IX_ResultRecord_DivisionId | PRIMARY       | 8  | Extent3.InputEntity_Id | 1 | Using where         | 
| 1 | PRIMARY  | Extent4  | ref | IX_RA_AT,IX_RA_A_ID,IX_RA_RR_ID                                    | IX_RA_RR_ID      | 8  | Extent3.InputEntity_Id | 1 | Using where; Start temporary; End temporary | 
| 1 | PRIMARY  | Extent2  | ref | PRIMARY                                          | PRIMARY       | 8  | Extent3.InputEntity_Id | 1 |            | 
| 2 | MATERIALIZED | Extent3  | ref | IX_InputEntity_Id,IX_InputEntityIdentification_Type,IX_InputEntityIdentification_Number                      | IX_InputEntityIdentification_Type | 4  | const     | 1 | Using where         | 

現在,我有過這樣的問題,在整個系統中很多次,很顯然,它是與MySQL EF 6連接器決定總是包裹在一個查詢的問題子選擇應用ORDER BY,但僅在查詢中存在連接時使用。這是造成重大性能問題。我見過的一些答案建議修改連接器源代碼,但這可能很乏味,任何人都有這個相同的問題,知道解決方法,已經修改連接器或除了簡單地移動到SQL Server並將MySQL留下後,還有任何其他建議,因爲這不是一種選擇。

+0

不是一個不錯的選擇,但它看起來像你應該做內存中的排序。並在MySQL連接器上提出一個強大的功能請求。 –

+0

這是有問題的,主要是因爲這些請求可能帶來的數據量。我一定會提交功能請求。謝謝! – EduardoLozano94

回答

0

事實證明,爲了解決這個與MySQL驅動程序,你的整個lambda必須一次寫入。意思在一個地方(..)謂語。這樣司機就知道這是一個結果集。現在,如果你構建了一個初始的IQueryable,然後繼續附加Where子句來訪問子表,它會相信有多個結果集,因此會將整個查詢包裝到一個子選擇中,以便對其進行排序和限制。

0

你看看SQL Server生成的SQL嗎?是不同的還是隻有演出不同?

因爲[通常]不是決定查詢結構的提供者(即排序子查詢)。提供者只是將查詢的結構轉換爲DBMS的語法。所以,在你的情況下,問題可能是DBMS優化器。

在類似於您的問題中,我使用了基於將查詢映射到實體的不同方法,即使用ObjectContext.ExecuteStoreQuery

+0

我相信.ExecuteStoreQuery只是用來運行我編寫的普通SQL查詢。我們可能不得不走向這個問題,問題在於這些查詢是動態構建的,因此,目前擺脫LINQ將是一項艱鉅的任務。 – EduardoLozano94

+0

使用ExecuteStoreQuery,您可以運行您需要爲商店優化的查詢。通常只有很少的查詢需要針對DBMS進行優化(否則,您需要更改ORM,即使用Dapper)。大規模的upsert和刪除是最差的(SQL Server中的解決方案是使用批量複製,但對於MySQL,您不能使用相同的庫)。關於SQL,您是否看到查詢是否以相同的方式嵌套? – bubi

+0

是的,小巧玲瓏一直在討論中,不利的一面是我們現在需要大量的功能重寫來擺脫EF。而在SQL Server中,它不會嵌套。我在我的問題中發佈的第二個查詢是由MSSQL生成的。因此,讓我們知道用於EF的MySQL連接器是罪魁禍首。 – EduardoLozano94