Login ProductsSalesSupportDownloadsAbout |
Home » Technical Support » ElevateDB Technical Support » Support Forums » ElevateDB SQL » View Thread |
Messages 11 to 20 of 22 total |
Invoking functions from SELECT statements... |
Thu, Dec 12 2013 1:29 PM | Permanent Link |
Mario Enríquez Open Consult | Roy,
Yes, it is SQL mostly and DML sometimes, never DDL… The fnCalculateComision was just an example and not a real function, but here's the code to the real one: CREATE FUNCTION "fnInvExistenciaBodega" (IN "pIdProductoEmpresa" GUID COLLATE UNI, IN "pIdBodega" GUID COLLATE UNI, IN "pFechaMov" TIMESTAMP) RETURNS DECIMAL(19,4) BEGIN DECLARE Result DECIMAL(19,4) DEFAULT 0; EXECUTE IMMEDIATE ' SELECT px.bodega AS existencia INTO ? FROM inv_producto_existencia px INNER JOIN inv_bodega_ubicacion bu ON px.id_ubicacion = bu.id_ubicacion WHERE px.id_producto_empresa = ? AND px.fecha <= ? AND bu.id_bodega = ? ORDER BY px.fecha desc RANGE 0 TO 1' USING Result, pIdProductoEmpresa, pFechaMov, pIdBodega; RETURN COALESCE(Result, 0.0); END VERSION 1.00! This function is meant to return the available stock for and specific Item (pIdProductoEmpresa) on a specific Warehouse (pIdBodega) at a given time (pFechaMov). So if one would like to know the available stock for all items on a given warehouse, if possible with the following SELECT. SELECT id_producto_empresa, fnInvExistenciaBodega(id_producto_empresa, '', CURRENT_TIMESTAMP) AS existencia FROM inv_producto_empresa WHERE activo = 'S' Do you think there's way to overcome the preparation of the EXECUTE IMMEDIATE for each row? Thanks for taking the time! Regards, Mario |
Fri, Dec 13 2013 6:08 AM | Permanent Link |
Roy Lambert NLH Associates Team Elevate | Mario
It can be rewritten without the EXECUTE IMMEDIATE but wether it will be faster or not I don't know. You will need to test that. What you need to do before anything else is to ensure that the query you're using is as effective as you can make it. Run it as a simple query in EDBManager and use the execution plan to refine if necessary. Just looking at your code 1) I don't know if the RANGE clause is necessary and 2) ditto for the ORDER BY clause. I suspect not from your description of what you are doing. The function below could be totally wrong because I can't test, and I'm not the best with SQL on these NGs CREATE FUNCTION "fnInvExistenciaBodega" (IN "pIdProductoEmpresa" GUID COLLATE UNI, IN "pIdBodega" GUID COLLATE UNI, IN "pFechaMov" TIMESTAMP) RETURNS DECIMAL(19,4) BEGIN DECLARE Result DECIMAL(19,4) DEFAULT 0; DECLARE DBCursor CURSOR FOR DBStmt; PREPARE DBStmt FROM 'SELECT px.bodega AS existencia FROM inv_producto_existencia px INNER JOIN inv_bodega_ubicacion bu ON px.id_ubicacion = bu.id_ubicacion WHERE px.id_producto_empresa = ? AND px.fecha <= ? AND bu.id_bodega = ?'; OPEN DBCursor USING Result, pIdProductoEmpresa, pFechaMov, pIdBodega; FETCH FIRST FROM DBCursor ('existencia') INTO Result; RETURN COALESCE(Result, 0.0); END If it works and it's still not good enough I'd recommend opening a support ticket with Tim. Roy Lambert |
Fri, Dec 13 2013 3:15 PM | Permanent Link |
Mario Enríquez Open Consult | Thanks again Roy, I'll take another round at optimisation and hope for better results.
Regards, Mario |
Mon, Dec 16 2013 8:29 AM | Permanent Link |
Tim Young [Elevate Software] Elevate Software, Inc. timyoung@elevatesoft.com | Mario,
<< It is as if every time a row is processed the function call is prepared. Is this possible? >> No, all called functions are prepared once during the outer SQL preparation, and then left alone until the outer SQL is un-prepared. If you want to send me the database catalog and relevant table files, along with the SQL that you're using, I can profile it here and tell you what's going on. But, at first glance, my guess is the same as Roy's: the EXECUTE IMMEDIATE is incurring the cost of re-preparing the SQL in the function for each row, and that's what is taking up the time. Inside of any routine (function/procedure/script), the preparation state of statements is always a nested state based upon the outer SQL's preparation state. This is essentially what happens with your existing function: Prepare outer SQL - function is initialized but the EXECUTE IMMEDIATE is not prepared, etc. Execute outer SQL - function is executed for each relevant row, and the EXECUTE IMMEDIATE is executed for each row, incurring the cost of being prepared (including compilation/table opens), executed, and then destroyed. With Roy's version, this is what happens: Prepare outer SQL - function is initialized and the statement/cursor variables are initialized internally (but not prepared). Execute outer SQL - function is executed for each relevant row, and the first execution causes the statement variable to be prepared/executed. Subsequent row executions only incur the overhead of an additional execution (due to the explicit PREPARE in the function), and the function is only destroyed when the outer SQL is un-prepared. Basically, the rule about manually preparing SQL when you intend to execute it many times also applies to functions/procedures and the statements enclosed within them. Tim Young Elevate Software www.elevatesoft.com |
Mon, Dec 16 2013 1:02 PM | Permanent Link |
Mario Enríquez Open Consult | Tim,
Thank you for participating and explanation of the prepare/unprepare cycle. I've rewrote my function using Roy's advice, and create a copy to do some benchmarking, and unfortunately the response time is about the same. When an statement is declare inside a function/procedure does it get destroyed after the function is finished and the recreated in the next call? I would post a copy of the database for both of you to take a look. Meanwhile, here's a the modified version of the function… CREATE FUNCTION "fnInvExistenciaBodega2" (IN "pIdProductoEmpresa" GUID COLLATE UNI, IN "pIdBodega" GUID COLLATE UNI, IN "pFechaMov" TIMESTAMP) RETURNS DECIMAL(19,4) BEGIN DECLARE Result DECIMAL(19,4) DEFAULT 0; DECLARE curExs CURSOR FOR stmtExistencia; PREPARE stmtExistencia FROM ' SELECT px.bodega AS existencia FROM inv_producto_existencia px INNER JOIN inv_bodega_ubicacion bu ON px.id_ubicacion = bu.id_ubicacion WHERE px.id_producto_empresa = ? AND px.fecha <= ? AND bu.id_bodega = ? ORDER BY px.fecha desc RANGE 0 TO 1'; OPEN curExs USING pIdProductoEmpresa, pFechaMov, pIdBodega; FETCH FIRST FROM curExs('existencia') INTO Result; RETURN COALESCE(Result, 0.0); END VERSION 1.00! Regards, Mario |
Mon, Dec 16 2013 9:45 PM | Permanent Link |
Mario Enríquez Open Consult | Roy and Tim,
You can download a copy of the database from the following URL: http://www.open-consult.com/merkantus/FunctionTestDB.EDBBkp The download is about 65mb. Regards, Mario |
Tue, Dec 17 2013 4:27 AM | Permanent Link |
Roy Lambert NLH Associates Team Elevate | Mario
Is it ansi or unicode? Is there a download link? If I use the one you've supplied it just opens the backup for display in the browser. Roy Lambert |
Tue, Dec 17 2013 9:46 AM | Permanent Link |
Tim Young [Elevate Software] Elevate Software, Inc. timyoung@elevatesoft.com | Mario,
<< When an statement is declare inside a function/procedure does it get destroyed after the function is finished and the recreated in the next call? >> No, which is what I was attempting to explain. The outer SQL controls when the inner referenced functions are created/destroyed. Your link is bad, BTW. If you want, you can just email me the backup. Just make sure to specify whether it is Unicode or ANSI. Thanks, Tim Young Elevate Software www.elevatesoft.com |
Tue, Dec 17 2013 4:11 PM | Permanent Link |
Mario Enríquez Open Consult | Sorry for the broken link…
Please try again with this one: http://www.open-consult.com/merkantus/FunctionTestDB.zip regards, Mario |
Mon, Dec 30 2013 9:04 PM | Permanent Link |
Mario Enríquez Open Consult | Sorry, I forgot to mention the database its UNICODE. Regards, Mario |
« Previous Page | Page 2 of 3 | Next Page » |
Jump to Page: 1 2 3 |
This web page was last updated on Wednesday, May 15, 2024 at 08:40 PM | Privacy PolicySite Map © 2024 Elevate Software, Inc. All Rights Reserved Questions or comments ? E-mail us at info@elevatesoft.com |