在以下原始查询中:
SELECT COMPANYNAME,
(
SELECT SUM(RRP) * 0.1
FROM CRM_RESALE_ITEM_VIEW
INNER JOIN CRM_RESALE using (RESALE_ID)
WHERE CRM_RESALE.CUSTOMER_ID = CRM_CUSTOMER_VIEW.CUSTOMER_ID
) AS DERRIVED_MAINTENANCE
FROM CRM_CUSTOMER_VIEW
我已将DERRIVED_MAINTENANCE
子选项替换为如下:
SELECT COMPANYNAME,
F_MAINTENANCE(CRM_CUSTOMER_VIEW.CUSTOMER_ID) AS DERRIVED_MAINTENANCE
FROM CRM_CUSTOMER_VIEW
有一个功能:
BEGIN
DECLARE DERRIVED_MAINTENANCE DECIMAL DEFAULT 0;
SELECT SUM(RRP) * 0.1
INTO DERRIVED_MAINTENANCE
FROM CRM_RESALE_ITEM_VIEW
INNER JOIN CRM_RESALE using (RESALE_ID)
WHERE CRM_RESALE.CUSTOMER_ID = CUST_ID;
RETURN DERRIVED_MAINTENANCE;
END
现在,而不是花费60秒,查询永远不会返回。 任何人都可以看到这个原因吗?
CRM_CUSTOMER (CUSTOMER_ID) one-to-many with
CRM_RESALE (RESALE_ID, CUSTOMER_ID) one-to-many with
CRM_RESALE_ITEM_VIEW (RESALE_ID, ITEM_ID, RRP)
答案 0 :(得分:0)
TL; DR :通过正确的索引可以为您提供更好的服务。将JOIN
卸载到函数实际上可能会使事情变得更糟,更糟糕。 但是正确索引VIEW
并不简单,并且您没有提供足够的信息来提供有保证的解决方案。您可以在下面找到提案和评估的测试。
可能是函数 返回,但它需要很长时间。我在与原始查询大致相同的时间内返回(我的定义与您的定义不同,仔细检查我的代码,我可能会误解):
示例数据
CREATE TABLE CRM_CUSTOMER_VIEW
( CUSTOMER_ID INTEGER, COMPANYNAME VARCHAR(50) );
INSERT INTO CRM_CUSTOMER_VIEW VALUES ( 1, 'ACME' ), ( 2, 'NASA' );
SELECT @N:=COUNT(*) FROM CRM_CUSTOMER_VIEW;
INSERT INTO CRM_CUSTOMER_VIEW SELECT CUSTOMER_ID + @N, CONCAT(SUBSTRING(COMPANYNAME, 1, 4), ' ', @N, '.', CUSTOMER_ID)
FROM CRM_CUSTOMER_VIEW;
-- Repeat the two rows above to fill the table with, say, half a million records.
CREATE TABLE CRM_RESALE ( CUSTOMER_ID INTEGER, RESALE_ID INTEGER );
SELECT @N:=1;
INSERT INTO CRM_RESALE SELECT CUSTOMER_ID, 5*CUSTOMER_ID+@N FROM CRM_CUSTOMER_VIEW;
SELECT @N:=@N+1;
-- Repeat five times the two rows above to get five items per customer
CREATE TABLE CRM_RESALE_ITEM_VIEW ( RESALE_ID INTEGER, RRP NUMERIC(7,3));
INSERT INTO CRM_RESALE_ITEM_VIEW SELECT RESALE_ID, 3.14159 FROM CRM_RESALE;
现在我们运行查询以获得基线 - 没有索引,因此即使在快速机器上也非常昂贵
SELECT COMPANYNAME,
(
SELECT SUM(RRP) * 0.1
FROM CRM_RESALE_ITEM_VIEW
INNER JOIN CRM_RESALE using (RESALE_ID)
WHERE CRM_RESALE.CUSTOMER_ID = CRM_CUSTOMER_VIEW.CUSTOMER_ID
) AS DERRIVED_MAINTENANCE
FROM CRM_CUSTOMER_VIEW WHERE COMPANYNAME = 'ACME';
+-------------+----------------------+
| COMPANYNAME | DERRIVED_MAINTENANCE |
+-------------+----------------------+
| ACME | 1.5710 |
+-------------+----------------------+
1 row in set (3.18 sec)
现在我们将内部查询移动到它自己的函数中。
DELIMITER //
CREATE FUNCTION DERRIVED_MAINTENANCE ( CUSTID INTEGER )
RETURNS NUMERIC(7,3) DETERMINISTIC
BEGIN
SELECT SUM(RRP) * 0.1 INTO @SRRP
FROM CRM_RESALE_ITEM_VIEW
INNER JOIN CRM_RESALE using (RESALE_ID)
WHERE CRM_RESALE.CUSTOMER_ID = CUSTID;
RETURN @SRRP;
END//
DELIMITER ;
mysql> SELECT DERRIVED_MAINTENANCE(1);
+-------------------------+
| DERRIVED_MAINTENANCE(1) |
+-------------------------+
| 1.571 |
+-------------------------+
1 row in set (3.60 sec)
如果我针对FIVE行运行查询,我会五次,因为该函数被调用了五次。
SELECT CUSTOMER_ID, DERRIVED_MAINTENANCE(CUSTOMER_ID) FROM CRM_CUSTOMER_VIEW WHERE CUSTOMER_ID < 5;
+-------------+-----------------------------------+
| CUSTOMER_ID | DERRIVED_MAINTENANCE(CUSTOMER_ID) |
+-------------+-----------------------------------+
| 1 | 1.571 |
| 2 | 1.571 |
| 3 | 1.571 |
| 4 | 1.571 |
+-------------+-----------------------------------+
4 rows in set (14.45 sec)
如果我索引这些表,但使用覆盖索引 - 我可以这样做,因为它们是表格;您也可以为视图执行此操作,但您需要以不同的方式编制索引,并且可能您可以从不同的聚合视图中受益。如果不了解更多,就无法真正建议
CREATE INDEX CRM_RESALE_ITEM_VIEW_NDX ON CRM_RESALE_ITEM_VIEW(RESALE_ID, RRP);
CREATE INDEX CRM_RESALE_NDX ON CRM_RESALE (CUSTOMER_ID, RESALE_ID);
现在我可以使用VIEW
代替函数,或者调用函数:
CREATE VIEW CRM_RESALE_FULL_VIEW AS
SELECT CUSTOMER_ID, SUM(RRP) * 0.1 AS DERRIVED_MAINTENANCE
FROM CRM_RESALE_ITEM_VIEW
INNER JOIN CRM_RESALE using (RESALE_ID)
GROUP BY CUSTOMER_ID;
SELECT COMPANYNAME, DERRIVED_MAINTENANCE FROM CRM_CUSTOMER_VIEW JOIN CRM_RESALE_FULL_VIEW USING (CUSTOMER_ID) WHERE COMPANYNAME LIKE 'ACME 1024.20%';
+---------------+----------------------+
| COMPANYNAME | DERRIVED_MAINTENANCE |
+---------------+----------------------+
| ACME 1024.201 | 1.5710 |
| ACME 1024.203 | 1.5710 |
| ACME 1024.205 | 1.5710 |
| ACME 1024.207 | 1.5710 |
| ACME 1024.209 | 1.5710 |
+---------------+----------------------+
5 rows in set (1.11 sec)
SELECT COMPANYNAME, DERRIVED_MAINTENANCE FROM CRM_CUSTOMER_VIEW JOIN CRM_RESALE_FULL_VIEW USING (CUSTOMER_ID) WHERE COMPANYNAME LIKE 'ACME 1024.2%';
+---------------+----------------------+
| COMPANYNAME | DERRIVED_MAINTENANCE |
+---------------+----------------------+
| ACME 1024.21 | 1.5710 |
...
| ACME 1024.299 | 1.5710 |
+---------------+----------------------+
55 rows in set (1.31 sec)
或调用函数
SELECT CUSTOMER_ID, DERRIVED_MAINTENANCE(CUSTOMER_ID) FROM CRM_CUSTOMER_VIEW WHERE CUSTOMER_ID > 42 AND CUSTOMER_ID < 47;
SELECT CUSTOMER_ID, DERRIVED_MAINTENANCE(CUSTOMER_ID) FROM CRM_CUSTOMER_VIEW WHERE CUSTOMER_ID > 42 AND CUSTOMER_ID < 47;
+-------------+-----------------------------------+
| CUSTOMER_ID | DERRIVED_MAINTENANCE(CUSTOMER_ID) |
+-------------+-----------------------------------+
| 43 | 1.571 |
| 44 | 1.571 |
| 45 | 1.571 |
| 46 | 1.571 |
+-------------+-----------------------------------+
4 rows in set (0.03 sec)
单独建立索引可以使性能提升两个数量级。