ie.*_*ie. 6 stored-procedures advantage-database-server
我有一个关于ADS中存储过程性能的问题.我创建了一个具有以下结构的简单数据库:
CREATE TABLE MainTable
(
Id INTEGER PRIMARY KEY,
Name VARCHAR(50),
Value INTEGER
);
CREATE UNIQUE INDEX MainTableName_UIX ON MainTable ( Name );
CREATE TABLE SubTable
(
Id INTEGER PRIMARY KEY,
MainId INTEGER,
Name VARCHAR(50),
Value INTEGER
);
CREATE INDEX SubTableMainId_UIX ON SubTable ( MainId );
CREATE UNIQUE INDEX SubTableName_UIX ON SubTable ( Name );
CREATE PROCEDURE CreateItems
(
MainName VARCHAR ( 20 ),
SubName VARCHAR ( 20 ),
MainValue INTEGER,
SubValue INTEGER,
MainId INTEGER OUTPUT,
SubId INTEGER OUTPUT
)
BEGIN
DECLARE @MainName VARCHAR ( 20 );
DECLARE @SubName VARCHAR ( 20 );
DECLARE @MainValue INTEGER;
DECLARE @SubValue INTEGER;
DECLARE @MainId INTEGER;
DECLARE @SubId INTEGER;
@MainName = (SELECT MainName FROM __input);
@SubName = (SELECT SubName FROM __input);
@MainValue = (SELECT MainValue FROM __input);
@SubValue = (SELECT SubValue FROM __input);
@MainId = (SELECT MAX(Id)+1 FROM MainTable);
@SubId = (SELECT MAX(Id)+1 FROM SubTable );
INSERT INTO MainTable (Id, Name, Value) VALUES (@MainId, @MainName, @MainValue);
INSERT INTO SubTable (Id, Name, MainId, Value) VALUES (@SubId, @SubName, @MainId, @SubValue);
INSERT INTO __output SELECT @MainId, @SubId FROM system.iota;
END;
CREATE PROCEDURE UpdateItems
(
MainName VARCHAR ( 20 ),
MainValue INTEGER,
SubValue INTEGER
)
BEGIN
DECLARE @MainName VARCHAR ( 20 );
DECLARE @MainValue INTEGER;
DECLARE @SubValue INTEGER;
DECLARE @MainId INTEGER;
@MainName = (SELECT MainName FROM __input);
@MainValue = (SELECT MainValue FROM __input);
@SubValue = (SELECT SubValue FROM __input);
@MainId = (SELECT TOP 1 Id FROM MainTable WHERE Name = @MainName);
UPDATE MainTable SET Value = @MainValue WHERE Id = @MainId;
UPDATE SubTable SET Value = @SubValue WHERE MainId = @MainId;
END;
CREATE PROCEDURE SelectItems
(
MainName VARCHAR ( 20 ),
CalculatedValue INTEGER OUTPUT
)
BEGIN
DECLARE @MainName VARCHAR ( 20 );
@MainName = (SELECT MainName FROM __input);
INSERT INTO __output SELECT m.Value * s.Value FROM MainTable m INNER JOIN SubTable s ON m.Id = s.MainId WHERE m.Name = @MainName;
END;
CREATE PROCEDURE DeleteItems
(
MainName VARCHAR ( 20 )
)
BEGIN
DECLARE @MainName VARCHAR ( 20 );
DECLARE @MainId INTEGER;
@MainName = (SELECT MainName FROM __input);
@MainId = (SELECT TOP 1 Id FROM MainTable WHERE Name = @MainName);
DELETE FROM SubTable WHERE MainId = @MainId;
DELETE FROM MainTable WHERE Id = @MainId;
END;
Run Code Online (Sandbox Code Playgroud)
实际上,我遇到的问题 - 即使是如此轻的存储过程相对于普通查询(0-5ms)工作得非常慢(大约50-150毫秒).为了测试性能,我创建了一个简单的测试(在F#中使用ADS ADO.NET提供程序):
open System;
open System.Data;
open System.Diagnostics;
open Advantage.Data.Provider;
let mainName = "main name #";
let subName = "sub name #";
// INSERT
let cmdTextScriptInsert = "
DECLARE @MainId INTEGER;
DECLARE @SubId INTEGER;
@MainId = (SELECT MAX(Id)+1 FROM MainTable);
@SubId = (SELECT MAX(Id)+1 FROM SubTable );
INSERT INTO MainTable (Id, Name, Value) VALUES (@MainId, :MainName, :MainValue);
INSERT INTO SubTable (Id, Name, MainId, Value) VALUES (@SubId, :SubName, @MainId, :SubValue);
SELECT @MainId, @SubId FROM system.iota;";
let cmdTextProcedureInsert = "CreateItems";
// UPDATE
let cmdTextScriptUpdate = "
DECLARE @MainId INTEGER;
@MainId = (SELECT TOP 1 Id FROM MainTable WHERE Name = :MainName);
UPDATE MainTable SET Value = :MainValue WHERE Id = @MainId;
UPDATE SubTable SET Value = :SubValue WHERE MainId = @MainId;";
let cmdTextProcedureUpdate = "UpdateItems";
// SELECT
let cmdTextScriptSelect = "
SELECT m.Value * s.Value FROM MainTable m INNER JOIN SubTable s ON m.Id = s.MainId WHERE m.Name = :MainName;";
let cmdTextProcedureSelect = "SelectItems";
// DELETE
let cmdTextScriptDelete = "
DECLARE @MainId INTEGER;
@MainId = (SELECT TOP 1 Id FROM MainTable WHERE Name = :MainName);
DELETE FROM SubTable WHERE MainId = @MainId;
DELETE FROM MainTable WHERE Id = @MainId;";
let cmdTextProcedureDelete = "DeleteItems";
let cnnStr = @"data source=D:\DB\test.add; ServerType=local; user id=adssys; password=***;";
let cnn = new AdsConnection(cnnStr);
try
cnn.Open();
let cmd = cnn.CreateCommand();
let parametrize ix prms =
cmd.Parameters.Clear();
let addParam = function
| "MainName" -> cmd.Parameters.Add(":MainName" , mainName + ix.ToString()) |> ignore;
| "SubName" -> cmd.Parameters.Add(":SubName" , subName + ix.ToString() ) |> ignore;
| "MainValue" -> cmd.Parameters.Add(":MainValue", ix * 3 ) |> ignore;
| "SubValue" -> cmd.Parameters.Add(":SubValue" , ix * 7 ) |> ignore;
| _ -> ()
prms |> List.iter addParam;
let runTest testData =
let (cmdType, cmdName, cmdText, cmdParams) = testData;
let toPrefix cmdType cmdName =
let prefix = match cmdType with
| CommandType.StoredProcedure -> "Procedure-"
| CommandType.Text -> "Script -"
| _ -> "Unknown -"
in prefix + cmdName;
let stopWatch = new Stopwatch();
let runStep ix prms =
parametrize ix prms;
stopWatch.Start();
cmd.ExecuteNonQuery() |> ignore;
stopWatch.Stop();
cmd.CommandText <- cmdText;
cmd.CommandType <- cmdType;
let startId = 1500;
let count = 10;
for id in startId .. startId+count do
runStep id cmdParams;
let elapsed = stopWatch.Elapsed;
Console.WriteLine("Test '{0}' - total: {1}; per call: {2}ms", toPrefix cmdType cmdName, elapsed, Convert.ToInt32(elapsed.TotalMilliseconds)/count);
let lst = [
(CommandType.Text, "Insert", cmdTextScriptInsert, ["MainName"; "SubName"; "MainValue"; "SubValue"]);
(CommandType.Text, "Update", cmdTextScriptUpdate, ["MainName"; "MainValue"; "SubValue"]);
(CommandType.Text, "Select", cmdTextScriptSelect, ["MainName"]);
(CommandType.Text, "Delete", cmdTextScriptDelete, ["MainName"])
(CommandType.StoredProcedure, "Insert", cmdTextProcedureInsert, ["MainName"; "SubName"; "MainValue"; "SubValue"]);
(CommandType.StoredProcedure, "Update", cmdTextProcedureUpdate, ["MainName"; "MainValue"; "SubValue"]);
(CommandType.StoredProcedure, "Select", cmdTextProcedureSelect, ["MainName"]);
(CommandType.StoredProcedure, "Delete", cmdTextProcedureDelete, ["MainName"])];
lst |> List.iter runTest;
finally
cnn.Close();
Run Code Online (Sandbox Code Playgroud)
我得到以下结果:
测试'脚本 - 插入' - 总计:00:00:00.0292841; 每次通话:2ms
测试'脚本 - 更新' - 总计:00:00:00.0056296; 每次通话:0ms
测试'脚本 - 选择' - 总计:00:00:00.0051738; 每次通话:0ms
测试'Script -Delete' - 总计:00:00:00.0059258; 每次通话:0ms
测试'Procedure-Insert' - 总计:00:00:01.2567146; 每次通话:125ms
测试'程序 - 更新' - 总计:00:00:00.7442440; 每次通话:74ms
测试'程序选择' - 总计:00:00:00.5120446; 每次通话:51ms
测试'程序 - 删除' - 总计:00:00:01.0619165; 每次通话:106ms
远程服务器的情况要好得多,但是plaqin查询和存储过程之间仍然存在很大差距:
测试'Script -Insert' - 总计:00:00:00.0709299; 每次通话:7ms
测试'脚本 - 更新' - 总计:00:00:00.0161777; 每次通话:1ms
测试'脚本 - 选择' - 总计:00:00:00.0258113; 每次通话:2ms
测试'Script -Delete' - 总计:00:00:00.0166242; 每次通话:1ms
测试'Procedure-Insert' - 总计:00:00:00.5116138; 每次通话:51ms
测试'程序 - 更新' - 总计:00:00:00.3802251; 每次通话:38ms
测试'程序 - 选择' - 总计:00:00:00.1241245; 每次通话:12ms
测试'Procedure-Delete' - 总计:00:00:00.4336334; 每次通话:43ms
是否有机会提高SP性能?请指教.
ADO.NET驱动程序版本 - 9.10.2.9
服务器版本 - 9.10.0.9(ANSI - 德语,OEM - 德语)
谢谢!
的优势V10测试包括多种性能改进直接靶向存储过程的性能.以下是当前发货版本需要考虑的一些事项:
在您的CreateItems过程中,替换可能更有效
@MainName = (SELECT MainName FROM __input);
@SubName = (SELECT SubName FROM __input);
@MainValue = (SELECT MainValue FROM __input);
@SubValue = (SELECT SubValue FROM __input);
Run Code Online (Sandbox Code Playgroud)
使用单个游标来检索所有参数:
DECLARE input CURSOR;
OPEN input as SELECT * from __input;
FETCH input;
@MainName = input.MainName;
@SubName = input.SubName;
@MainValue = input.MainValue;
@SubValue = input.SubValue;
CLOSE input;
Run Code Online (Sandbox Code Playgroud)
这将避免3个语句解析/语义/优化/执行操作只是为了检索输入参数(我知道,我们真的需要完全消除__input表).
SelectItems过程很少会像客户端中的select一样快,特别是在这种情况下,除了抽象参数值(可以在客户端轻松完成)之外,它实际上没有做任何事情.请记住,因为它是一个JOIN,所以填充__output表的SELECT将是一个静态游标(意味着服务器要创建和填充的内部临时文件),但现在另外还有__output表,这是另一个服务器的临时文件,加上你有额外的开销用这个__output表填充已经放在静态游标临时表中的数据,只是为了复制它(服务器可以更好地检测这个并替换__output与现有的静态游标引用,但它目前没有).
我会尝试做一些时间来尝试版本10.你的程序如果您在测试中使用的测试表中随意压缩起来,并将它们发送到Advantage@iAnywhere.com并把经办人:JD中的主题.
有一个改变将有助于该CreateItems程序.更改以下两个语句:
@MainId = (SELECT MAX(Id)+1 FROM MainTable);
@SubId = (SELECT MAX(Id)+1 FROM SubTable );
Run Code Online (Sandbox Code Playgroud)
对此:
@MainId = (SELECT MAX(Id) FROM MainTable);
@MainId = @MainId + 1;
@SubId = (SELECT MAX(Id) FROM SubTable );
@SubId = @SubId + 1;
Run Code Online (Sandbox Code Playgroud)
我查看了该语句的第一个版本的查询计划信息(在Advantage Data Architect中).看起来优化器不会将其MAX(id)+1分解为组件.select max(id) from maintable可以使用ID字段上的索引优化该语句.它似乎max(id)+1没有优化.因此,随着表的增长,进行这种改变将是相当重要的.
另一件可能有用的事情是在CACHE PREPARE ON;每个脚本的顶部添加一个语句.这可以在多次运行时帮助执行某些过程.
编辑 的优势V10测试版今天发布.所以我CreateItems用v9.1和新的beta版本运行你的程序.我对远程服务器运行了1000次迭代.速度差异显着:
v9.1: 101 seconds
v10 beta: 2.2 seconds
Run Code Online (Sandbox Code Playgroud)
请注意,我使用select max(id)上面描述的更改运行了一个版本.这个测试是在我相当老的开发PC上进行的.
| 归档时间: |
|
| 查看次数: |
2138 次 |
| 最近记录: |