MySQL 中的视图性能
Posted
技术标签:
【中文标题】MySQL 中的视图性能【英文标题】:Performance on View in MySQL 【发布时间】:2016-07-18 09:22:05 【问题描述】:我已经在这样的表上创建了一个视图:
CREATE OR REPLACE VIEW V_BLA AS
SELECT
CONVERT(UIT_DNR USING latin1) AS internNr,
UIT_SNR AS schuldnr,
TRIM((SELECT SCH_OMS FROM BUSCHU WHERE SCH_DNR = UIT_DNR AND SCH_VNR = UIT_SNR)) AS omschrijving,
CASE
WHEN (SELECT TABDATA FROM BDTABE WHERE TABNR = 9000 AND VOLGNR = 1 AND TABTAAL = 0) = 1 THEN -- ALGEMEEN BESTAND
(SELECT CONCAT(TRIM(SC_FNAAM), ' ', TRIM(SC_VNAAM)) FROM SDSCIN WHERE SC_NR = LEFT(UIT_SCHULDEISER, 4))
ELSE
(SELECT CONCAT(TRIM(SC_FNAAM), ' ', TRIM(SC_VNAAM)) FROM BUSCIN WHERE SC_NR = 100000 - UIT_SCHULDEISER)
END AS schuldeiser,
UIT_DATUM AS datum,
UIT_VLGNR AS volgnummer,
UIT_BEDRAG AS bedrag,
CONVERT(IF(
UIT_COBE_DAT = 0,
NULL,
CONCAT(
RIGHT(UIT_COBE_DAT, 4), '-',
IF(UIT_COBE_DAT < 10000000,
CONCAT(MID(UIT_COBE_DAT, 2, 2), '-0', LEFT(UIT_COBE_DAT, 1)),
CONCAT(MID(UIT_COBE_DAT, 3, 2), '-', LEFT(UIT_COBE_DAT, 2))
))), DATE) AS datumBetaallijst,
TRIM(UIT_MEDEDELING) AS mededeling
FROM BUUITG;
问题是性能真的很差。当我尝试通过 internNr 选择一些行时,生成输出最多需要 10 秒。我已经创建了必要的索引:
BDTABE:在 BDTABE(TABNR,VOLGNR)上创建索引 BDTABE_TABNR_VOLGNR; SDSCIN:在 SDSCIN(SC_NR) 上创建索引 SDSCIN_SC_NR; BUSCIN:在 BUSCIN(SC_NR) 上创建索引 BUSCIN_SC_NR;BUUITG 上的 UIT_DNR 上的额外索引并没有改善任何东西。
我做选择时的解释计划:
EXPLAIN SELECT * FROM V_BLA WHERE interNr = 'something';
+---+--------------------+------------+-----+------------------------+------------------------+----+-----------------------------------------------------------+--------+--------+-----------------------------------------------------+
| 1 | PRIMARY | <derived2> | ref | <auto_key0> | <auto_key0> | 22 | const | 10 | 100.00 | Using where |
+---+--------------------+------------+-----+------------------------+------------------------+----+-----------------------------------------------------------+--------+--------+-----------------------------------------------------+
| 2 | DERIVED | BUUITG | ALL | | | | | 208498 | 100.00 | |
| 6 | DEPENDENT SUBQUERY | BUSCIN | ref | BUSCIN_SC_NR | BUSCIN_SC_NR | 4 | func | 1 | 100.00 | Using index condition |
| 5 | DEPENDENT SUBQUERY | | | | | | | | | Impossible WHERE noticed after reading const tables |
| 4 | SUBQUERY | BDTABE | ref | BDTABE_TABNR_VOLGNR | BDTABE_TABNR_VOLGNR | 14 | const,const | 1 | 100.00 | Using where |
| 3 | DEPENDENT SUBQUERY | BUSCHU | ref | BUSCHU_SCH_VNR_SCH_DNR | BUSCHU_SCH_VNR_SCH_DNR | 12 | export_winsoc.BUUITG.UIT_SNR,export_winsoc.BUUITG.UIT_DNR | 1 | 100.00 | |
+---+--------------------+------------+-----+------------------------+------------------------+----+-----------------------------------------------------------+--------+--------+-----------------------------------------------------+
【问题讨论】:
您是否尝试过将子查询从选择列表移动到from
子句中的派生表/简单连接?
我无法更改表结构...
我没有要求你改变你的表结构...
我现在明白你的要求了。你的建议对我来说描述得不够好。
也许您应该熟悉派生表的概念。它们对于编写更复杂的查询非常重要。
【参考方案1】:
正如评论中已经指出的,我会将选择列表中的子查询移动到from
子句,或者作为简单的连接,或者作为派生表。我使用左连接,但可以根据您的要求和数据随意将它们更改为内连接。请同时检查连接条件,因为在某些情况下我不得不猜测哪些字段在哪些表中。
CREATE OR REPLACE VIEW V_BLA AS
SELECT
CONVERT(UIT_DNR USING latin1) AS internNr,
UIT_SNR AS schuldnr,
TRIM(BUSCHU.SCH_OMS ) AS omschrijving,
CASE
WHEN BDTABE.TABDATA = 1 THEN -- ALGEMEEN BESTAND
CONCAT(TRIM(SDSCIN.SC_FNAAM), ' ', TRIM(SDSCIN.SC_VNAAM))
ELSE
CONCAT(TRIM(BUSCIN.SC_FNAAM), ' ', TRIM(BUSCIN.SC_VNAAM)
END AS schuldeiser,
UIT_DATUM AS datum,
UIT_VLGNR AS volgnummer,
UIT_BEDRAG AS bedrag,
CONVERT(IF(
UIT_COBE_DAT = 0,
NULL,
CONCAT(
RIGHT(UIT_COBE_DAT, 4), '-',
IF(UIT_COBE_DAT < 10000000,
CONCAT(MID(UIT_COBE_DAT, 2, 2), '-0', LEFT(UIT_COBE_DAT, 1)),
CONCAT(MID(UIT_COBE_DAT, 3, 2), '-', LEFT(UIT_COBE_DAT, 2))
))), DATE) AS datumBetaallijst,
TRIM(UIT_MEDEDELING) AS mededeling
FROM BUUITG
LEFT JOIN BUSCHU ON BUSCHU.SCH_DNR=BUUITG.UIT_DNR AND BUSCHU.SCH_VNR=BUUITG.UIT_VNR
LEFT JOIN BDTABE ON BDTABE.TABNR = 9000 AND BDTABE.VOLGNR = 1 AND BDTABE.TABTAAL = 0 --did not find any common fields between the 2 tables
LEFT JOIN SDSCIN ON SDSCIN.SC_NR = LEFT(BUUITGUIT_SCHULDEISER, 4)
LEFT JOIN BUSCIN ON BUSCIN.SC_NR = 100000 - BUUITG.UIT_SCHULDEISER
【讨论】:
所以,我尝试了你的方法,但它只会让事情变得更糟:(。性能下降了大约 15%。 您是否有适当的索引来支持连接,例如 SCH_DNR 和 SCH_VNR 字段?如果确实使用过,您是否使用说明检查过? 是的,正确的索引在那里。它使用所有正确的索引,除了它对 BUUITG 本身进行全表扫描。 1.在您的问题中,SCH_DNR 和 SCH_VNR 字段上没有提到索引... 2. 这并不奇怪,因为 BUUITG 位于连接表达式的左侧,并且没有应用过滤器。 事实上,我创建了 8 个视图。在创建其他视图之一时,我之前在 SCH_DNR 和 SCH_VNR 上创建了索引。有趣的是,这是最不复杂的查询视图,它给我带来了很多问题......【参考方案2】:CONVERT(UIT_DNR USING latin1) AS internNr
防止在UIT_DNR
上使用索引,这对于您提供解释的查询似乎至关重要。 (别介意错字:internr vs internnr。)
那是你的连接参数?什么是SHOW VARIABLES LIKE 'char%
'?请为每张桌子提供SHOW CREATE TABLE
。
看看是否把那一行改成
UIT_DNR AS internNr
添加
INDEX(UIT_DNR, UIT_BEDRAG)
会有帮助。
【讨论】:
以上是关于MySQL 中的视图性能的主要内容,如果未能解决你的问题,请参考以下文章