【问题标题】:What indices or reorganization might improve the query time of this database?哪些索引或重组可能会改善此数据库的查询时间?
【发布时间】:2016-01-23 23:41:18
【问题描述】:

我的数据库存储游戏中的项目列表以及有关它们的相关信息。

主项目表包含所有只能有单个条目的字段,例如重量、简短描述等。

可能是一组值的字段由具有 2 个字段、项目 ID 和属性 ID 的表表示,例如允许使用该项目的种族列表或可能佩戴该项目的地点列表.在连接中导致大量额外行的是与项目关联的影响列表和影响的值(例如:影响 allowed_carrying_weight 10 或影响生命值 20 或两者都不影响或两者兼而有之)。

其中一些通过使用位域以编程方式存储在 1 个字段中,例如,每个种族都有一个数字,如果允许种族使用该项目,则将设置 AllowedRaceInteger & 2^(raceNumber)

例如,背包可以拿在手中或背在背上。也许这个特殊的背包可能只有人类和精灵才能使用。

SELECT DISTINCT i.id, iwt.wearlocID, i.sdesc, i.wearProg, i.isOOG, i.minLvl, i.maxLvl, 
    iaft.affectID, iaft.amount, NULL AS affectbyID FROM item i 
INNER JOIN itemwearTable iwt ON i.id=iwt.itemID 
LEFT JOIN itemaffectTable iaft ON i.id=iaft.itemID 
WHERE iwt.wearlocID >= 1 AND iwt.wearlocID <= 22 AND i.minlvl <= 50 
UNION 
SELECT DISTINCT i.id, iwt.wearlocID, i.sdesc, i.wearProg, i.isOOG, i.minLvl, i.maxLvl, 
    NULL AS affectID, NULL AS amount, iafbt.affectbyID FROM item i 
INNER JOIN itemwearTable iwt ON i.id=iwt.itemID 
LEFT JOIN itemaffectedbyTable iafbt ON i.id=iafbt.itemID 
WHERE iwt.wearlocID >= 1 AND iwt.wearlocID <= 22 AND i.minlvl <= 50 
ORDER BY wearlocID, sdesc,id

即使在非常小的数据集上,此查询也可能需要 7-10 秒才能执行。我设置的唯一索引是 item.id。我可以使用什么标准来决定是否应该对事物进行索引?例如,是否应该为我的表中将项目与值相关联的所有值编入索引,否则会产生新问题吗?

这一切都可以通过位域编码来简化吗?我不认为它可以,因为它需要沿着 select * 从某处 wheresomewhere.field & 256 == 1 ..

谢谢

【问题讨论】:

    标签: sql join database-performance


    【解决方案1】:

    数据库优化

    至少,值得在itemwearTableitemaffectTableitemaffectedbyTable 中为itemId 建立索引。索引外键几乎总是一个好主意。

    我在此查询中看到的唯一其他候选索引是wearlocID。但是,索引是否会产生影响在很大程度上取决于列的基数(即该列可以包含多少不同的值)。

    查询优化

    如果可以预期第一个和第二个查询返回不同的结果,则使用UNION ALL 而不是UNION 可能会有所帮助。 UNION 消除了重复,这往往会导致查询被排序,成本更高。

    您似乎两次运行相同的基本查询,但最终联接有所不同。您可能会受益于使用公用表表达式 (CTE)。这允许您运行一次查询并多次引用结果。

    实施这两个建议如下所示:

    WITH src 
         AS (SELECT DISTINCT i.id, 
                             iwt.wearlocid, 
                             i.sdesc, 
                             i.wearprog, 
                             i.isoog, 
                             i.minlvl, 
                             i.maxlvl 
             FROM   item i 
                    inner join itemweartable iwt 
                            ON i.id = iwt.itemid 
             WHERE  iwt.wearlocid >= 1 
                    AND iwt.wearlocid <= 22 
                    AND i.minlvl <= 50) 
    SELECT DISTINCT src.id, 
                    src.wearlocid, 
                    src.sdesc, 
                    src.wearprog, 
                    src.isoog, 
                    src.minlvl, 
                    src.maxlvl, 
                    iaft.affectid, 
                    iaft.amount, 
                    NULL AS affectbyID 
    FROM   src 
           left join itemaffecttable iaft 
                  ON src.id = iaft.itemid 
    UNION ALL 
    SELECT DISTINCT src.id, 
                    src.wearlocid, 
                    src.sdesc, 
                    src.wearprog, 
                    src.isoog, 
                    src.minlvl, 
                    src.maxlvl, 
                    NULL AS affectID, 
                    NULL AS amount, 
                    iafbt.affectbyid 
    FROM   src 
           left join itemaffectedbytable iafbt 
                  ON src.id = iafbt.itemid 
    ORDER  BY wearlocid, 
              sdesc, 
              id 
    

    其他说明

    您似乎从该查询中的每个表中获取了每一行。这是一个真正的用例吗?如果不尝试使用更接近您实际期望应用程序运行的查询(例如,如果它一次运行一个项目的此查询)。通常,尝试从每个表中获取每一行的执行方式与更有针对性的查询不同。

    【讨论】:

    • 这是通用查询,还有其他联合将选择限制为远少于每一行。然而,这在第一次加载时很典型。我将探索 CTE,我以前从未听说过(不是 db 专业人士)。我会尝试建立索引,看看会发生什么样的性能变化。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-18
    • 2010-12-16
    • 2016-03-19
    • 1970-01-01
    相关资源
    最近更新 更多