【问题标题】:SQL Access query speedSQL Access 查询速度
【发布时间】:2013-03-15 06:35:30
【问题描述】:

我的 Access 2003 数据库中有以下查询:

SELECT 
    Projet.OTP AS OTP, 
    NumeroDA, 
    SUM(Quantite*PrixReelCommande) AS PrixTotal, 
    FIRST(Fournisseur1) AS Fournisseur, 
    FIRST(Projet.NumeroCommandeReservation) AS NumeroCommande, 
    FIRST(Projet.GestionContrat) AS GestionContrat, 
    FIRST(Projet.Acheteur) AS Acheteur, 
    MIN(DateLivraisonContractuelle) AS DateLivraisonContrat, 
    MAX(DateFournisseurLivraison) AS DateLivraisonFournisseur, 
    FIRST(InfoProjet.NomInstallation) AS NomInstallation, 
    FIRST(InfoProjet.TitreMandat) AS TitreMandat
FROM Projet LEFT JOIN InfoProjet ON Projet.OTP=InfoProjet.OTP
WHERE NumeroDA Like "#*" And NumeroDA IN (
                                            SELECT NumeroDA FROM Projet 
                                            WHERE NumeroCommandeReservation="" Or NumeroCommandeReservation Is Null Or NumeroCommandeReservation="0"
                                        )
GROUP BY Projet.OTP, Projet.NumeroDA
ORDER BY Projet.OTP, Projet.NumeroDA

表格 Projet 有大约 2500 行,而 InfoProjet 只有 200 行。在 Access 中打开此表中的任何一个都需要不到 1 秒的时间。但是,执行上述查询需要超过 5 秒。

我想知道是否可以采取任何措施来提高此查询的性能。查询中是否有一些我应该避免性能方面的东西?或者我只是在访问限制下?我猜想在子查询中使用Like 并没有帮助,但一定有其他东西会减慢查询速度。

【问题讨论】:

  • 两张表的 [OTP] 上都有索引吗?如果是这样,索引是否包括列 NumeroDA。你有关于 NumeroCommandeReservation 的索引,以及包括 NumeroDA 吗?
  • OTP 上没有索引,有多行具有相同的 OTP。但是我们可以在 Access 中设置非唯一索引,您认为在这种情况下会有所帮助吗?对于 NumeroDA 也是如此,有多个行具有相同的 NumeraDA 和 NumeroCommandeReservation。 PK 是 NumeroListe 和 NumeroArticle,两者都使用重复支持进行索引。
  • 不一定要唯一,非唯一索引也可以帮助查询,如果可以创建复合索引或者覆盖索引,对你的帮助更大。

标签: sql ms-access query-performance


【解决方案1】:

由于您没有在子查询中使用任何 Distincts,您能否通过删除该部分来简化它? (虽然我现在不能测试这个,所以我不完全确定它会给出相同的结果)

SELECT 
    Projet.OTP AS OTP, 
    NumeroDA, 
    SUM(Quantite*PrixReelCommande) AS PrixTotal, 
    FIRST(Fournisseur1) AS Fournisseur, 
    FIRST(Projet.NumeroCommandeReservation) AS NumeroCommande, 
    FIRST(Projet.GestionContrat) AS GestionContrat, 
    FIRST(Projet.Acheteur) AS Acheteur, 
    MIN(DateLivraisonContractuelle) AS DateLivraisonContrat, 
    MAX(DateFournisseurLivraison) AS DateLivraisonFournisseur, 
    FIRST(InfoProjet.NomInstallation) AS NomInstallation, 
    FIRST(InfoProjet.TitreMandat) AS TitreMandat
FROM Projet LEFT JOIN InfoProjet ON Projet.OTP=InfoProjet.OTP
WHERE NumeroDA Like "#*" And (
     NumeroCommandeReservation="" Or 
     NumeroCommandeReservation Is Null Or 
     NumeroCommandeReservation="0")

GROUP BY Projet.OTP, Projet.NumeroDA
ORDER BY Projet.OTP, Projet.NumeroDA

【讨论】:

  • 它确实有效,并且在不到一秒的时间内给了我相同的结果。所以问题是带有IN() 函数的子查询。好像Access不喜欢它。我会接受你的回答,因为它确实解决了我的问题,我现在会更加小心。这个查询可能还可以改进。
  • 为了改进查询,那些First() 语句让我有点紧张。他们可能隐藏了一些重要的事情。我建议摆脱那些 First() 语句,而是将这些字段放在 Group By 语句中。有意义吗?
【解决方案2】:

尝试运行它,看看它返回了多少行:

SELECT COUNT(*)
FROM Projet LEFT JOIN InfoProjet ON Projet.OTP=InfoProjet.OTP
WHERE NumeroDA Like "#*" And NumeroDA IN (
                                        SELECT NumeroDA FROM Projet 
                                        WHERE NumeroCommandeReservation="" 
                                        Or NumeroCommandeReservation Is Null 
                                        Or NumeroCommandeReservation="0"
                                    )

原因:Join 可能会返回您所期望的更多行,但由于您只有 MAX/MIN/FIRST 聚合,您可能不会注意到。

【讨论】:

  • 原来的查询只返回23行,没关系。我刚试过你的查询,和我原来的查询一样长,它返回的计数是 111。
  • @dnLL 在这种情况下,我认为唯一有帮助的是按照 ljh 的建议添加索引或重写查询以删除子查询并将其移动到连接或 where 部分。
  • PowerUser 的解决方案实际上解决了我的问题,但我也会考虑添加索引。
猜你喜欢
  • 1970-01-01
  • 2022-11-11
  • 2016-11-22
  • 2014-08-01
  • 1970-01-01
  • 2015-04-07
  • 2016-02-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多