Page 1 of 2

Feature request:TMSQuery.GenerateParametrizedSQL

Posted: Mon 20 Dec 2010 10:40
by brace
Considering http://www.devart.com/forums/viewtopic. ... highlight= and http://www.devart.com/forums/viewtopic. ... highlight= I have a feature request (a good reason to buy SDAC upgrade ;)):

inrtoduce a new behaviour, different than the "TDataSet one", for ParamByName. for example it could be a new property called TMSQuery.GenerateParametrizedSQL.

Let's consdier a MSQuery1 for which the SQL is

Code: Select all

select * from table where ID = :ID 
doing

Code: Select all

MSQuery1.ParamByName('ID').AsInteger := 45;
MSQuery1.Open;

CASE 1: MSQuery1.GenerateParametrizedSQL is True (default) the query sent to the server will be a parametrized one (current behaviour):

Code: Select all

exec sp_executesql N'select * from table where ID = @P1',N'@P1 int',45
CASE 2: MSQuery1.GenerateParametrizedSQL is False the query sent to the server will be a "hardcoded" query (NEW required behaviour):

Code: Select all

select * from table where ID = 45 -- simple Search&Replace performed by ParamByName!!!
It is clear that in some scenarios (exepcially when the queries are executed only once or when there are performance problems as described in the linked posts, the developer has an immediate benefit in changing the value of the property!).

Please comment on this suggestion.

======================

As an extra reference for why this is useful please see also this question on StackOverflow I posted: http://stackoverflow.com/questions/4408 ... parameters

Posted: Tue 21 Dec 2010 08:27
by AndreyZ
Hello,

We have investigated this question. We don't plan to implement this functionality until it is requested by several users. But you can get similar functionality by using macros instead of parameters. Here is an example:

Code: Select all

  MSQuery.SQL.Text := 'select * from &TestTable where id = &TestID';
  MSQuery.MacroByName('TestTable').Value := 'tbltest';
  MSQuery.MacroByName('TestID').AsInteger := 10;
  MSQuery.Open;

Posted: Tue 21 Dec 2010 11:44
by brace
Thanks for the reply and the suggestion.

Of course my request come because I have tons of lines of code where I use ParamByName.

Anyway now that you told me about this MacroByName feature may be the suggestion can be modified, like this:

the new property could be

ParametersBehaviour and as values pbDefault, pbMacro (if the second is chosen ParamByName behaves like MacroByName, but without the need to use & instead of :.

This is slightly more userfriendly.

Posted: Tue 21 Dec 2010 14:53
by AndreyZ
You can implement the functionality you need in the following way:

Code: Select all

procedure TMainForm.btnOpenClick(Sender: TObject);
begin
  MSQuery.SQL.Text := 'select * from tbltest where testid = :testid and teststr = :teststr';
  MSQuery.ParamByName('testid').AsInteger := 10;
  MSQuery.ParamByName('teststr').AsString := 'test';
  MSQuery.Open;
end;

procedure TMainForm.MSQueryBeforeOpen(DataSet: TDataSet);
var
  sqlt: string;
  i: integer;
  q: TMSQuery;
begin
  q := TMSQuery(DataSet);
  sqlt := q.SQL.Text;
  for i := 0 to q.ParamCount - 1 do
    sqlt := AnsiReplaceText(sqlt, ':' + q.Params[i].Name, QuotedStr(q.Params[i].AsString));
  q.SQL.Text := sqlt;
end;

Posted: Tue 21 Dec 2010 15:52
by brace
Thanks this is a good suggestion.

THe problem is that I have many TMSQuery in different datamodules, รจ some of the defined in code, like

Code: Select all

MyQuery := TMSQuery.Create;
  MyQuery.Sql.Text := 'select * from tbltest where testid = :testid and teststr = :teststr'; 
  etc...
Moreover I am already using BeforeOpen event in some cases.

Could you suggest a centralized solution?

Posted: Wed 22 Dec 2010 14:37
by AndreyZ
You can create the following class:

Code: Select all

TDummy = class
  class procedure BeforeOpen(DataSet: TDataSet);
end;

class procedure TDummy.BeforeOpen(DataSet: TDataSet);
var
  sqlt: string;
  i: integer;
  q: TMSQuery;
begin
  q := TMSQuery(DataSet);
  sqlt := q.SQL.Text;
  for i := 0 to q.ParamCount - 1 do
    sqlt := AnsiReplaceText(sqlt, ':' + q.Params[i].Name, QuotedStr(q.Params[i].AsString));
  q.SQL.Text := sqlt;
end;
and use this functionality when you need it in the following way:

Code: Select all

procedure TMainForm.btnOpenClick(Sender: TObject);
begin
  MSQuery.BeforeOpen := TDummy.BeforeOpen;
  MSQuery.SQL.Text := 'select * from tbltest where testid = :testid and teststr = :teststr';
  MSQuery.ParamByName('testid').AsInteger := 10;
  MSQuery.ParamByName('teststr').AsString := 'test';
  MSQuery.Open;
end;

Posted: Thu 23 Dec 2010 10:15
by brace
Ok thanks for the suggestion, anyway after discovering this I feel that the performance of my application is improving of a factor 2 by using these "no parameterized queries", either with marco by name or with the technique you suggested.

So i would say now that ParamsByName is a "niche approach" that should be taken only in some particular cases.

And I will vote again for my suggestion, because I guess it will "for free" improve the performance of many other SDAC powered applications.

(the suggestion I made in the past that you implemented about OpenDataSets really made a terrific improvement in the performance when the server latency is high, here it is the same basic idea: "simple thing, great benefit" - of course this particular suggestion will make the query faster, it doesn't deal with server latency).

Posted: Thu 23 Dec 2010 12:35
by AndreyZ
We will investigate the possibility of adding this functionality in the future. As soon as we solve this question we will let you know.

Posted: Tue 17 May 2011 14:40
by brace
Just a quick post to ask it yo made any progress on this investigation.

Posted: Wed 18 May 2011 06:30
by AnHa
Can you review http://devart.uservoice.com/forums/1046 ... ?ref=title , if this is what you want and add a vote?
As seen in other feature request's: more votes -> higher priority for implementing!

Posted: Wed 18 May 2011 08:56
by AndreyZ
Thank you, AnHa.
If there are many voices for this suggestion at uservoice, we will implement it.

Posted: Thu 19 May 2011 12:55
by brace
Ok I did, thanks. Now the score is 5.

Anyway I strongly suggest to do this, SQL Server performance with parametrized queries is terrible with many complex queries.

I was forced to use MacroByName in many places at least to gain some 200% speed improvement (it occurs with queries with many joins and many parameters tipically).

PS: By the way this is not a task like "create a seprate product for SQLLite" or "Rewrite the driver", it is quite easy and it would give a great performance improvement to all users, I don't think everyone is profiling as I don, so I may guess that many users don't know about this big issue (that is not linked to DevArt, but to SQL Server itself, anyway by adding 1 property DevArt could help the developers to bypass the SQL Server problem).

Posted: Thu 19 May 2011 14:34
by AndreyZ
For the time being we have tasks of higher priority, and we don't have any term for implementing this functionality.

Posted: Thu 19 May 2011 15:02
by brace
is there a published roadmap?

Posted: Fri 20 May 2011 06:51
by AndreyZ
We don't have any public roadmap. For the time being our chief priority task is to add support of 64bit environment to all DAC products.
From now on we implement new features basing on their necessity (it's determined by our users voices). This way we can implement features that most of our users want to see in our products.
We will implement the feature you suggested, but we cannot provide any timeframe.