0

次の元のクエリでは:

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)
4

1 に答える 1

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 行に対してクエリを実行すると、関数が 5 回呼び出されるため、5 倍の長さになります。

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);

これで、関数の代わりに a を使用するか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)

インデックスを作成するだけで、パフォーマンスが 2 桁向上します。

于 2013-10-29T13:04:03.307 に答える