TClientDataSet uses too much memory for string fieldsMidasLib.dcu makes the application slowerRestructure a TClientdatasetFiltering A TClientDataSet On A NestedDataSet FieldAre TClientDataSets part of your toolkit, or have they been replaced by something else?current focussed field of a TClientDataSetTClientDataSet Doesn't Release MemoryWhy does't OnEditError or OnPostError catch an invalid user entry in TClientDataSet?TClientDataSet and limit by memoryTClientDataSet Missing Data ProviderHow to affect Delphi XEx code generation for Android/ARM targets?Delphi TClientDataset refreshing memory table

A man in the desert is bitten by a skeletal animal, its skull gets stuck on his arm

Will some rockets really collapse under their own weight?

How do I call a 6-digit Australian phone number with a US-based mobile phone?

Is there a fallacy about "appeal to 'big words'"?

Output the list of musical notes

Souce that you can't you tell your wife not to lend to others?

Sums of binomial coefficients weighted by incomplete gamma

Unconventional examples of mathematical modelling

Solving pricing problem heuristically in column generation algorithm for VRP

Telephone number in spoken words

Why does this Jet Provost strikemaster have a textured leading edge?

What modifiers are added to the attack and damage rolls of this unique longbow from Waterdeep: Dragon Heist?

What can I do to increase the amount of LEDs I can power with a pro micro?

Would the USA be eligible to join the European Union?

Units of measurement, especially length, when body parts vary in size among races

Is there a word for returning to unpreparedness?

The more + the + comparative degree

Solving a maximum minimum problem

A+ rating still unsecure by Google Chrome's opinion

How to prevent criminal gangs from making/buying guns?

Are there liquid fueled rocket boosters having coaxial fuel/oxidizer tanks?

How can I find an old paper when the usual methods fail?

Suspension compromise for urban use

Is there a name for the technique in songs/poems, where the rhyming pattern primes the listener for a certain line, which never comes?



TClientDataSet uses too much memory for string fields


MidasLib.dcu makes the application slowerRestructure a TClientdatasetFiltering A TClientDataSet On A NestedDataSet FieldAre TClientDataSets part of your toolkit, or have they been replaced by something else?current focussed field of a TClientDataSetTClientDataSet Doesn't Release MemoryWhy does't OnEditError or OnPostError catch an invalid user entry in TClientDataSet?TClientDataSet and limit by memoryTClientDataSet Missing Data ProviderHow to affect Delphi XEx code generation for Android/ARM targets?Delphi TClientDataset refreshing memory table






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








6















I was triggered to ask this question when trying to support this question with an MCVE.



I recently started noticing that TClientDataSet quickly runs out of memory. I had an issue in production where it couldn't load a dataset with about 60.000, which seemed surprisingly low to me. The client dataset was connected through a provider with an ADODataSet, which loaded fine. I ran that query separately and outputted the result to CSV, which gave me a file of < 30MB.



So I made a small test, where I can load up to about 165K records in the client dataset, which has a string field with a size of 4000. The actual value of the field is only 3 characters, but that doesn't seem to matter for the result.



It looks like each record takes up at least those 4000 characters. 4000 x 2 bytes x 165K records = 1.3GB, so that starts closing in to the 32 bit memory limit.
If I turn it into a memo field, I can easily add 5 million rows.



program ClientDataSetTest;
$APPTYPE CONSOLE
uses SysUtils, DB, DBClient;

var
c: TClientDataSet;
i: Integer;
begin
c := TClientDataSet.Create(nil);
c.FieldDefs.Add('Id', ftInteger);
c.FieldDefs.Add('Test', ftString, 4000); // Actually claims this much space...
//c.FieldDefs.Add('Test', ftMemo); // Way more space efficient (and not notably slower)
//c.FieldDefs.Add('Test', ftMemo, 1); // But specifying size doesn't have any effect.
c.CreateDataSet;

try
i := 0;
while i < 5000000 do
begin
c.Append;
c['Id'] := i;
c['Test'] := 'xyz';
c.Post;

if (i mod 1000) = 0 then
WriteLn(i, c['Test']);

Inc(i);
end;

except
on e: Exception do
begin
c.Cancel;
WriteLn('Error adding row', i);
Writeln(e.ClassName, ': ', e.Message);
end;
end;

c.SaveToFile('c:tempoutput.xml', dfXML);
Writeln('Press ''any'' key');
ReadLn;
end.


So the question(s) themselves are a bit broad, but I'd like to have a solution for this and be able to load larger data sets by using the string space a bit more efficient. The reason the field is large, is because they can contain an annotation. For most records those will be empty or short though, so it's a tremendous waste of space.



  • Can TClientDataSet be configured in such a way that it handles this differently? I browsed its properties, but I can't find anything that seems related to this.

  • Can it be solved by using a different field type? I though of ftMemo, but that has some other disadvantages, like the size not being used for truncation, and some display issues, like TDBGrid displaying it as (MEMO), instead of the actual value.

  • Are there drop-in replacements for TClientDataSet that solve this? It's not just about the in-memory part, but also about the communication with ADO components through a TProvider, which is the main way I use it in this project, so not any memory dataset would do the trick.

For that last point, I happened to find this question, where hidden away in comments, vgLib is mentioned, but all I find about that is broken links, and I don't even know if it would solve this issue. Apparently the C++ code for MidasLib is available now, but since it's 1.5MB of obscure code, I thought it might be worth asking here before I dive into that. ;)










share|improve this question





















  • 1





    FWIW, the (MEMO) displayed in the grid can be easily fixed using the field's OnGetText event. I use it all the time to display the first handful of characters in the grid, and open a form with a memo control when the row is double-clicked to display the full content. The truncation can be handled in OnBeforePost.

    – Ken White
    Mar 27 at 12:05











  • @KenWhite Thanks for the suggestions! That is definitely an option for specific cases if a more generic solution isn't available. It does mean that the field type in the ADO dataset has to be memo too, otherwise that gives me errors. And that means I have to return it as a clob from my query, otherwise I get an error from the ADO Dataset. I'd have to figure out what the impact is of that, but it's no trivial change.

    – GolezTrol
    Mar 27 at 12:17






  • 1





    I guess I should have said addressed instead of easily fixed. :-)

    – Ken White
    Mar 27 at 12:31






  • 1





    Yeah, minutes would be an issue. Didn't realize Oracle was involved. Just out of curiosity, are the Direct Oracle Access (DOA) components still around? They were vastly better than ADO or Delphi's own drivers when working with Delphi and Oracle. Just checked - they are, at AllRoundAutomations

    – Ken White
    Mar 27 at 12:34







  • 1





    They are around, and I have used those for specific situation. But my project is 1 million lines and thousands of ADO components, so it's no easy fix to replace them all. Some is tricky too, because then I have two connections, and I have to be careful not trying to mix those in one transaction. But I ran the query in PLSQL Developer as well (also by AllroundAutomations, probably using their DAC) but there the query is a lot slower as well, although seemingly faster than in Delphi.... Sorry I left out all that context, but it felt as noice in the original question.

    – GolezTrol
    Mar 27 at 12:41


















6















I was triggered to ask this question when trying to support this question with an MCVE.



I recently started noticing that TClientDataSet quickly runs out of memory. I had an issue in production where it couldn't load a dataset with about 60.000, which seemed surprisingly low to me. The client dataset was connected through a provider with an ADODataSet, which loaded fine. I ran that query separately and outputted the result to CSV, which gave me a file of < 30MB.



So I made a small test, where I can load up to about 165K records in the client dataset, which has a string field with a size of 4000. The actual value of the field is only 3 characters, but that doesn't seem to matter for the result.



It looks like each record takes up at least those 4000 characters. 4000 x 2 bytes x 165K records = 1.3GB, so that starts closing in to the 32 bit memory limit.
If I turn it into a memo field, I can easily add 5 million rows.



program ClientDataSetTest;
$APPTYPE CONSOLE
uses SysUtils, DB, DBClient;

var
c: TClientDataSet;
i: Integer;
begin
c := TClientDataSet.Create(nil);
c.FieldDefs.Add('Id', ftInteger);
c.FieldDefs.Add('Test', ftString, 4000); // Actually claims this much space...
//c.FieldDefs.Add('Test', ftMemo); // Way more space efficient (and not notably slower)
//c.FieldDefs.Add('Test', ftMemo, 1); // But specifying size doesn't have any effect.
c.CreateDataSet;

try
i := 0;
while i < 5000000 do
begin
c.Append;
c['Id'] := i;
c['Test'] := 'xyz';
c.Post;

if (i mod 1000) = 0 then
WriteLn(i, c['Test']);

Inc(i);
end;

except
on e: Exception do
begin
c.Cancel;
WriteLn('Error adding row', i);
Writeln(e.ClassName, ': ', e.Message);
end;
end;

c.SaveToFile('c:tempoutput.xml', dfXML);
Writeln('Press ''any'' key');
ReadLn;
end.


So the question(s) themselves are a bit broad, but I'd like to have a solution for this and be able to load larger data sets by using the string space a bit more efficient. The reason the field is large, is because they can contain an annotation. For most records those will be empty or short though, so it's a tremendous waste of space.



  • Can TClientDataSet be configured in such a way that it handles this differently? I browsed its properties, but I can't find anything that seems related to this.

  • Can it be solved by using a different field type? I though of ftMemo, but that has some other disadvantages, like the size not being used for truncation, and some display issues, like TDBGrid displaying it as (MEMO), instead of the actual value.

  • Are there drop-in replacements for TClientDataSet that solve this? It's not just about the in-memory part, but also about the communication with ADO components through a TProvider, which is the main way I use it in this project, so not any memory dataset would do the trick.

For that last point, I happened to find this question, where hidden away in comments, vgLib is mentioned, but all I find about that is broken links, and I don't even know if it would solve this issue. Apparently the C++ code for MidasLib is available now, but since it's 1.5MB of obscure code, I thought it might be worth asking here before I dive into that. ;)










share|improve this question





















  • 1





    FWIW, the (MEMO) displayed in the grid can be easily fixed using the field's OnGetText event. I use it all the time to display the first handful of characters in the grid, and open a form with a memo control when the row is double-clicked to display the full content. The truncation can be handled in OnBeforePost.

    – Ken White
    Mar 27 at 12:05











  • @KenWhite Thanks for the suggestions! That is definitely an option for specific cases if a more generic solution isn't available. It does mean that the field type in the ADO dataset has to be memo too, otherwise that gives me errors. And that means I have to return it as a clob from my query, otherwise I get an error from the ADO Dataset. I'd have to figure out what the impact is of that, but it's no trivial change.

    – GolezTrol
    Mar 27 at 12:17






  • 1





    I guess I should have said addressed instead of easily fixed. :-)

    – Ken White
    Mar 27 at 12:31






  • 1





    Yeah, minutes would be an issue. Didn't realize Oracle was involved. Just out of curiosity, are the Direct Oracle Access (DOA) components still around? They were vastly better than ADO or Delphi's own drivers when working with Delphi and Oracle. Just checked - they are, at AllRoundAutomations

    – Ken White
    Mar 27 at 12:34







  • 1





    They are around, and I have used those for specific situation. But my project is 1 million lines and thousands of ADO components, so it's no easy fix to replace them all. Some is tricky too, because then I have two connections, and I have to be careful not trying to mix those in one transaction. But I ran the query in PLSQL Developer as well (also by AllroundAutomations, probably using their DAC) but there the query is a lot slower as well, although seemingly faster than in Delphi.... Sorry I left out all that context, but it felt as noice in the original question.

    – GolezTrol
    Mar 27 at 12:41














6












6








6








I was triggered to ask this question when trying to support this question with an MCVE.



I recently started noticing that TClientDataSet quickly runs out of memory. I had an issue in production where it couldn't load a dataset with about 60.000, which seemed surprisingly low to me. The client dataset was connected through a provider with an ADODataSet, which loaded fine. I ran that query separately and outputted the result to CSV, which gave me a file of < 30MB.



So I made a small test, where I can load up to about 165K records in the client dataset, which has a string field with a size of 4000. The actual value of the field is only 3 characters, but that doesn't seem to matter for the result.



It looks like each record takes up at least those 4000 characters. 4000 x 2 bytes x 165K records = 1.3GB, so that starts closing in to the 32 bit memory limit.
If I turn it into a memo field, I can easily add 5 million rows.



program ClientDataSetTest;
$APPTYPE CONSOLE
uses SysUtils, DB, DBClient;

var
c: TClientDataSet;
i: Integer;
begin
c := TClientDataSet.Create(nil);
c.FieldDefs.Add('Id', ftInteger);
c.FieldDefs.Add('Test', ftString, 4000); // Actually claims this much space...
//c.FieldDefs.Add('Test', ftMemo); // Way more space efficient (and not notably slower)
//c.FieldDefs.Add('Test', ftMemo, 1); // But specifying size doesn't have any effect.
c.CreateDataSet;

try
i := 0;
while i < 5000000 do
begin
c.Append;
c['Id'] := i;
c['Test'] := 'xyz';
c.Post;

if (i mod 1000) = 0 then
WriteLn(i, c['Test']);

Inc(i);
end;

except
on e: Exception do
begin
c.Cancel;
WriteLn('Error adding row', i);
Writeln(e.ClassName, ': ', e.Message);
end;
end;

c.SaveToFile('c:tempoutput.xml', dfXML);
Writeln('Press ''any'' key');
ReadLn;
end.


So the question(s) themselves are a bit broad, but I'd like to have a solution for this and be able to load larger data sets by using the string space a bit more efficient. The reason the field is large, is because they can contain an annotation. For most records those will be empty or short though, so it's a tremendous waste of space.



  • Can TClientDataSet be configured in such a way that it handles this differently? I browsed its properties, but I can't find anything that seems related to this.

  • Can it be solved by using a different field type? I though of ftMemo, but that has some other disadvantages, like the size not being used for truncation, and some display issues, like TDBGrid displaying it as (MEMO), instead of the actual value.

  • Are there drop-in replacements for TClientDataSet that solve this? It's not just about the in-memory part, but also about the communication with ADO components through a TProvider, which is the main way I use it in this project, so not any memory dataset would do the trick.

For that last point, I happened to find this question, where hidden away in comments, vgLib is mentioned, but all I find about that is broken links, and I don't even know if it would solve this issue. Apparently the C++ code for MidasLib is available now, but since it's 1.5MB of obscure code, I thought it might be worth asking here before I dive into that. ;)










share|improve this question
















I was triggered to ask this question when trying to support this question with an MCVE.



I recently started noticing that TClientDataSet quickly runs out of memory. I had an issue in production where it couldn't load a dataset with about 60.000, which seemed surprisingly low to me. The client dataset was connected through a provider with an ADODataSet, which loaded fine. I ran that query separately and outputted the result to CSV, which gave me a file of < 30MB.



So I made a small test, where I can load up to about 165K records in the client dataset, which has a string field with a size of 4000. The actual value of the field is only 3 characters, but that doesn't seem to matter for the result.



It looks like each record takes up at least those 4000 characters. 4000 x 2 bytes x 165K records = 1.3GB, so that starts closing in to the 32 bit memory limit.
If I turn it into a memo field, I can easily add 5 million rows.



program ClientDataSetTest;
$APPTYPE CONSOLE
uses SysUtils, DB, DBClient;

var
c: TClientDataSet;
i: Integer;
begin
c := TClientDataSet.Create(nil);
c.FieldDefs.Add('Id', ftInteger);
c.FieldDefs.Add('Test', ftString, 4000); // Actually claims this much space...
//c.FieldDefs.Add('Test', ftMemo); // Way more space efficient (and not notably slower)
//c.FieldDefs.Add('Test', ftMemo, 1); // But specifying size doesn't have any effect.
c.CreateDataSet;

try
i := 0;
while i < 5000000 do
begin
c.Append;
c['Id'] := i;
c['Test'] := 'xyz';
c.Post;

if (i mod 1000) = 0 then
WriteLn(i, c['Test']);

Inc(i);
end;

except
on e: Exception do
begin
c.Cancel;
WriteLn('Error adding row', i);
Writeln(e.ClassName, ': ', e.Message);
end;
end;

c.SaveToFile('c:tempoutput.xml', dfXML);
Writeln('Press ''any'' key');
ReadLn;
end.


So the question(s) themselves are a bit broad, but I'd like to have a solution for this and be able to load larger data sets by using the string space a bit more efficient. The reason the field is large, is because they can contain an annotation. For most records those will be empty or short though, so it's a tremendous waste of space.



  • Can TClientDataSet be configured in such a way that it handles this differently? I browsed its properties, but I can't find anything that seems related to this.

  • Can it be solved by using a different field type? I though of ftMemo, but that has some other disadvantages, like the size not being used for truncation, and some display issues, like TDBGrid displaying it as (MEMO), instead of the actual value.

  • Are there drop-in replacements for TClientDataSet that solve this? It's not just about the in-memory part, but also about the communication with ADO components through a TProvider, which is the main way I use it in this project, so not any memory dataset would do the trick.

For that last point, I happened to find this question, where hidden away in comments, vgLib is mentioned, but all I find about that is broken links, and I don't even know if it would solve this issue. Apparently the C++ code for MidasLib is available now, but since it's 1.5MB of obscure code, I thought it might be worth asking here before I dive into that. ;)







delphi delphi-10-seattle tclientdataset






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Mar 27 at 11:59







GolezTrol

















asked Mar 27 at 11:09









GolezTrolGolezTrol

102k10 gold badges143 silver badges179 bronze badges




102k10 gold badges143 silver badges179 bronze badges










  • 1





    FWIW, the (MEMO) displayed in the grid can be easily fixed using the field's OnGetText event. I use it all the time to display the first handful of characters in the grid, and open a form with a memo control when the row is double-clicked to display the full content. The truncation can be handled in OnBeforePost.

    – Ken White
    Mar 27 at 12:05











  • @KenWhite Thanks for the suggestions! That is definitely an option for specific cases if a more generic solution isn't available. It does mean that the field type in the ADO dataset has to be memo too, otherwise that gives me errors. And that means I have to return it as a clob from my query, otherwise I get an error from the ADO Dataset. I'd have to figure out what the impact is of that, but it's no trivial change.

    – GolezTrol
    Mar 27 at 12:17






  • 1





    I guess I should have said addressed instead of easily fixed. :-)

    – Ken White
    Mar 27 at 12:31






  • 1





    Yeah, minutes would be an issue. Didn't realize Oracle was involved. Just out of curiosity, are the Direct Oracle Access (DOA) components still around? They were vastly better than ADO or Delphi's own drivers when working with Delphi and Oracle. Just checked - they are, at AllRoundAutomations

    – Ken White
    Mar 27 at 12:34







  • 1





    They are around, and I have used those for specific situation. But my project is 1 million lines and thousands of ADO components, so it's no easy fix to replace them all. Some is tricky too, because then I have two connections, and I have to be careful not trying to mix those in one transaction. But I ran the query in PLSQL Developer as well (also by AllroundAutomations, probably using their DAC) but there the query is a lot slower as well, although seemingly faster than in Delphi.... Sorry I left out all that context, but it felt as noice in the original question.

    – GolezTrol
    Mar 27 at 12:41













  • 1





    FWIW, the (MEMO) displayed in the grid can be easily fixed using the field's OnGetText event. I use it all the time to display the first handful of characters in the grid, and open a form with a memo control when the row is double-clicked to display the full content. The truncation can be handled in OnBeforePost.

    – Ken White
    Mar 27 at 12:05











  • @KenWhite Thanks for the suggestions! That is definitely an option for specific cases if a more generic solution isn't available. It does mean that the field type in the ADO dataset has to be memo too, otherwise that gives me errors. And that means I have to return it as a clob from my query, otherwise I get an error from the ADO Dataset. I'd have to figure out what the impact is of that, but it's no trivial change.

    – GolezTrol
    Mar 27 at 12:17






  • 1





    I guess I should have said addressed instead of easily fixed. :-)

    – Ken White
    Mar 27 at 12:31






  • 1





    Yeah, minutes would be an issue. Didn't realize Oracle was involved. Just out of curiosity, are the Direct Oracle Access (DOA) components still around? They were vastly better than ADO or Delphi's own drivers when working with Delphi and Oracle. Just checked - they are, at AllRoundAutomations

    – Ken White
    Mar 27 at 12:34







  • 1





    They are around, and I have used those for specific situation. But my project is 1 million lines and thousands of ADO components, so it's no easy fix to replace them all. Some is tricky too, because then I have two connections, and I have to be careful not trying to mix those in one transaction. But I ran the query in PLSQL Developer as well (also by AllroundAutomations, probably using their DAC) but there the query is a lot slower as well, although seemingly faster than in Delphi.... Sorry I left out all that context, but it felt as noice in the original question.

    – GolezTrol
    Mar 27 at 12:41








1




1





FWIW, the (MEMO) displayed in the grid can be easily fixed using the field's OnGetText event. I use it all the time to display the first handful of characters in the grid, and open a form with a memo control when the row is double-clicked to display the full content. The truncation can be handled in OnBeforePost.

– Ken White
Mar 27 at 12:05





FWIW, the (MEMO) displayed in the grid can be easily fixed using the field's OnGetText event. I use it all the time to display the first handful of characters in the grid, and open a form with a memo control when the row is double-clicked to display the full content. The truncation can be handled in OnBeforePost.

– Ken White
Mar 27 at 12:05













@KenWhite Thanks for the suggestions! That is definitely an option for specific cases if a more generic solution isn't available. It does mean that the field type in the ADO dataset has to be memo too, otherwise that gives me errors. And that means I have to return it as a clob from my query, otherwise I get an error from the ADO Dataset. I'd have to figure out what the impact is of that, but it's no trivial change.

– GolezTrol
Mar 27 at 12:17





@KenWhite Thanks for the suggestions! That is definitely an option for specific cases if a more generic solution isn't available. It does mean that the field type in the ADO dataset has to be memo too, otherwise that gives me errors. And that means I have to return it as a clob from my query, otherwise I get an error from the ADO Dataset. I'd have to figure out what the impact is of that, but it's no trivial change.

– GolezTrol
Mar 27 at 12:17




1




1





I guess I should have said addressed instead of easily fixed. :-)

– Ken White
Mar 27 at 12:31





I guess I should have said addressed instead of easily fixed. :-)

– Ken White
Mar 27 at 12:31




1




1





Yeah, minutes would be an issue. Didn't realize Oracle was involved. Just out of curiosity, are the Direct Oracle Access (DOA) components still around? They were vastly better than ADO or Delphi's own drivers when working with Delphi and Oracle. Just checked - they are, at AllRoundAutomations

– Ken White
Mar 27 at 12:34






Yeah, minutes would be an issue. Didn't realize Oracle was involved. Just out of curiosity, are the Direct Oracle Access (DOA) components still around? They were vastly better than ADO or Delphi's own drivers when working with Delphi and Oracle. Just checked - they are, at AllRoundAutomations

– Ken White
Mar 27 at 12:34





1




1





They are around, and I have used those for specific situation. But my project is 1 million lines and thousands of ADO components, so it's no easy fix to replace them all. Some is tricky too, because then I have two connections, and I have to be careful not trying to mix those in one transaction. But I ran the query in PLSQL Developer as well (also by AllroundAutomations, probably using their DAC) but there the query is a lot slower as well, although seemingly faster than in Delphi.... Sorry I left out all that context, but it felt as noice in the original question.

– GolezTrol
Mar 27 at 12:41






They are around, and I have used those for specific situation. But my project is 1 million lines and thousands of ADO components, so it's no easy fix to replace them all. Some is tricky too, because then I have two connections, and I have to be careful not trying to mix those in one transaction. But I ran the query in PLSQL Developer as well (also by AllroundAutomations, probably using their DAC) but there the query is a lot slower as well, although seemingly faster than in Delphi.... Sorry I left out all that context, but it felt as noice in the original question.

– GolezTrol
Mar 27 at 12:41













2 Answers
2






active

oldest

votes


















2














There is a difference between the way that the blob fields (memo) and regular fields store and retrieve their data. Blob fields don't store data in the record buffer (see TBlobField.GetDataSize) and they use a different set of methods when storing or retrieving that data.



The size of each record is returned by the call to TField.GetDataSize. For the TStringField, this is the required string size + 1.



TCustomClientDataSet.InitBufferPointers uses this as part of it's calculation for the value of FRecBufSize which is used as the memory size to allocate for each record in TCustomClientDataSet.AllocRecordBuffer.



So, to answer your questions:



  • TClientDataSet can't be configured to do this any differently.

  • It can be solved by other field types but they would have to descend from TBlobField. The buffer size is allocated up front so the regular fields can't contain different sizes depending on their contents.

  • I am not sure about drop in replacements. Dev Express have a dxMemData but I don't know whether it runs into the same problems or if it is a drop in replacement.





share|improve this answer

























  • Clear, thanks for the insight. It's indeed the way it's allocates. I was kinda hoping a way to influence that, but you've made it clear that that's not an option with the client dataset as it is.

    – GolezTrol
    Mar 28 at 10:50


















2














whenever I need rather long "string" field in CDS I tend to create memo one instead. besides aforementioned display issue (which can be addressed rather painless) there are few other restrictions so I have custom cds descendant. hyperbase (not vglib) internal string format is the same so it won't change anything in that regard. btw there are dacs (such as firedac) allowing to customize and choose target field type mapping. not sure whether ado components could be patched/enhanced to achieve similar functionality though. moreover iirc firedac dataset has the option to control internal string field layout ("inline" in-row buffer or just pointer to dynamically allocated one), but isn't 1:1 replacement for cds.






share|improve this answer

























  • Interesting, especially the option to control the internal string field layout. I was hoping that was possible in TClientDataSet as well, but it seems not, but indeed, if I can find a good way to map a char or varchar query result to a memo field, I can also make it a memo field in the client dataset. I think that is probably the best way forward.

    – GolezTrol
    Mar 28 at 10:49











  • if replacing ado with different dac isn't an option check its internals to see whether it is possible to implement field type mapping feature there

    – vavan
    Mar 29 at 13:22













Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55375774%2ftclientdataset-uses-too-much-memory-for-string-fields%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









2














There is a difference between the way that the blob fields (memo) and regular fields store and retrieve their data. Blob fields don't store data in the record buffer (see TBlobField.GetDataSize) and they use a different set of methods when storing or retrieving that data.



The size of each record is returned by the call to TField.GetDataSize. For the TStringField, this is the required string size + 1.



TCustomClientDataSet.InitBufferPointers uses this as part of it's calculation for the value of FRecBufSize which is used as the memory size to allocate for each record in TCustomClientDataSet.AllocRecordBuffer.



So, to answer your questions:



  • TClientDataSet can't be configured to do this any differently.

  • It can be solved by other field types but they would have to descend from TBlobField. The buffer size is allocated up front so the regular fields can't contain different sizes depending on their contents.

  • I am not sure about drop in replacements. Dev Express have a dxMemData but I don't know whether it runs into the same problems or if it is a drop in replacement.





share|improve this answer

























  • Clear, thanks for the insight. It's indeed the way it's allocates. I was kinda hoping a way to influence that, but you've made it clear that that's not an option with the client dataset as it is.

    – GolezTrol
    Mar 28 at 10:50















2














There is a difference between the way that the blob fields (memo) and regular fields store and retrieve their data. Blob fields don't store data in the record buffer (see TBlobField.GetDataSize) and they use a different set of methods when storing or retrieving that data.



The size of each record is returned by the call to TField.GetDataSize. For the TStringField, this is the required string size + 1.



TCustomClientDataSet.InitBufferPointers uses this as part of it's calculation for the value of FRecBufSize which is used as the memory size to allocate for each record in TCustomClientDataSet.AllocRecordBuffer.



So, to answer your questions:



  • TClientDataSet can't be configured to do this any differently.

  • It can be solved by other field types but they would have to descend from TBlobField. The buffer size is allocated up front so the regular fields can't contain different sizes depending on their contents.

  • I am not sure about drop in replacements. Dev Express have a dxMemData but I don't know whether it runs into the same problems or if it is a drop in replacement.





share|improve this answer

























  • Clear, thanks for the insight. It's indeed the way it's allocates. I was kinda hoping a way to influence that, but you've made it clear that that's not an option with the client dataset as it is.

    – GolezTrol
    Mar 28 at 10:50













2












2








2







There is a difference between the way that the blob fields (memo) and regular fields store and retrieve their data. Blob fields don't store data in the record buffer (see TBlobField.GetDataSize) and they use a different set of methods when storing or retrieving that data.



The size of each record is returned by the call to TField.GetDataSize. For the TStringField, this is the required string size + 1.



TCustomClientDataSet.InitBufferPointers uses this as part of it's calculation for the value of FRecBufSize which is used as the memory size to allocate for each record in TCustomClientDataSet.AllocRecordBuffer.



So, to answer your questions:



  • TClientDataSet can't be configured to do this any differently.

  • It can be solved by other field types but they would have to descend from TBlobField. The buffer size is allocated up front so the regular fields can't contain different sizes depending on their contents.

  • I am not sure about drop in replacements. Dev Express have a dxMemData but I don't know whether it runs into the same problems or if it is a drop in replacement.





share|improve this answer













There is a difference between the way that the blob fields (memo) and regular fields store and retrieve their data. Blob fields don't store data in the record buffer (see TBlobField.GetDataSize) and they use a different set of methods when storing or retrieving that data.



The size of each record is returned by the call to TField.GetDataSize. For the TStringField, this is the required string size + 1.



TCustomClientDataSet.InitBufferPointers uses this as part of it's calculation for the value of FRecBufSize which is used as the memory size to allocate for each record in TCustomClientDataSet.AllocRecordBuffer.



So, to answer your questions:



  • TClientDataSet can't be configured to do this any differently.

  • It can be solved by other field types but they would have to descend from TBlobField. The buffer size is allocated up front so the regular fields can't contain different sizes depending on their contents.

  • I am not sure about drop in replacements. Dev Express have a dxMemData but I don't know whether it runs into the same problems or if it is a drop in replacement.






share|improve this answer












share|improve this answer



share|improve this answer










answered Mar 28 at 1:46









GraymatterGraymatter

5,6352 gold badges22 silver badges44 bronze badges




5,6352 gold badges22 silver badges44 bronze badges















  • Clear, thanks for the insight. It's indeed the way it's allocates. I was kinda hoping a way to influence that, but you've made it clear that that's not an option with the client dataset as it is.

    – GolezTrol
    Mar 28 at 10:50

















  • Clear, thanks for the insight. It's indeed the way it's allocates. I was kinda hoping a way to influence that, but you've made it clear that that's not an option with the client dataset as it is.

    – GolezTrol
    Mar 28 at 10:50
















Clear, thanks for the insight. It's indeed the way it's allocates. I was kinda hoping a way to influence that, but you've made it clear that that's not an option with the client dataset as it is.

– GolezTrol
Mar 28 at 10:50





Clear, thanks for the insight. It's indeed the way it's allocates. I was kinda hoping a way to influence that, but you've made it clear that that's not an option with the client dataset as it is.

– GolezTrol
Mar 28 at 10:50













2














whenever I need rather long "string" field in CDS I tend to create memo one instead. besides aforementioned display issue (which can be addressed rather painless) there are few other restrictions so I have custom cds descendant. hyperbase (not vglib) internal string format is the same so it won't change anything in that regard. btw there are dacs (such as firedac) allowing to customize and choose target field type mapping. not sure whether ado components could be patched/enhanced to achieve similar functionality though. moreover iirc firedac dataset has the option to control internal string field layout ("inline" in-row buffer or just pointer to dynamically allocated one), but isn't 1:1 replacement for cds.






share|improve this answer

























  • Interesting, especially the option to control the internal string field layout. I was hoping that was possible in TClientDataSet as well, but it seems not, but indeed, if I can find a good way to map a char or varchar query result to a memo field, I can also make it a memo field in the client dataset. I think that is probably the best way forward.

    – GolezTrol
    Mar 28 at 10:49











  • if replacing ado with different dac isn't an option check its internals to see whether it is possible to implement field type mapping feature there

    – vavan
    Mar 29 at 13:22















2














whenever I need rather long "string" field in CDS I tend to create memo one instead. besides aforementioned display issue (which can be addressed rather painless) there are few other restrictions so I have custom cds descendant. hyperbase (not vglib) internal string format is the same so it won't change anything in that regard. btw there are dacs (such as firedac) allowing to customize and choose target field type mapping. not sure whether ado components could be patched/enhanced to achieve similar functionality though. moreover iirc firedac dataset has the option to control internal string field layout ("inline" in-row buffer or just pointer to dynamically allocated one), but isn't 1:1 replacement for cds.






share|improve this answer

























  • Interesting, especially the option to control the internal string field layout. I was hoping that was possible in TClientDataSet as well, but it seems not, but indeed, if I can find a good way to map a char or varchar query result to a memo field, I can also make it a memo field in the client dataset. I think that is probably the best way forward.

    – GolezTrol
    Mar 28 at 10:49











  • if replacing ado with different dac isn't an option check its internals to see whether it is possible to implement field type mapping feature there

    – vavan
    Mar 29 at 13:22













2












2








2







whenever I need rather long "string" field in CDS I tend to create memo one instead. besides aforementioned display issue (which can be addressed rather painless) there are few other restrictions so I have custom cds descendant. hyperbase (not vglib) internal string format is the same so it won't change anything in that regard. btw there are dacs (such as firedac) allowing to customize and choose target field type mapping. not sure whether ado components could be patched/enhanced to achieve similar functionality though. moreover iirc firedac dataset has the option to control internal string field layout ("inline" in-row buffer or just pointer to dynamically allocated one), but isn't 1:1 replacement for cds.






share|improve this answer













whenever I need rather long "string" field in CDS I tend to create memo one instead. besides aforementioned display issue (which can be addressed rather painless) there are few other restrictions so I have custom cds descendant. hyperbase (not vglib) internal string format is the same so it won't change anything in that regard. btw there are dacs (such as firedac) allowing to customize and choose target field type mapping. not sure whether ado components could be patched/enhanced to achieve similar functionality though. moreover iirc firedac dataset has the option to control internal string field layout ("inline" in-row buffer or just pointer to dynamically allocated one), but isn't 1:1 replacement for cds.







share|improve this answer












share|improve this answer



share|improve this answer










answered Mar 28 at 8:00









vavanvavan

4052 silver badges8 bronze badges




4052 silver badges8 bronze badges















  • Interesting, especially the option to control the internal string field layout. I was hoping that was possible in TClientDataSet as well, but it seems not, but indeed, if I can find a good way to map a char or varchar query result to a memo field, I can also make it a memo field in the client dataset. I think that is probably the best way forward.

    – GolezTrol
    Mar 28 at 10:49











  • if replacing ado with different dac isn't an option check its internals to see whether it is possible to implement field type mapping feature there

    – vavan
    Mar 29 at 13:22

















  • Interesting, especially the option to control the internal string field layout. I was hoping that was possible in TClientDataSet as well, but it seems not, but indeed, if I can find a good way to map a char or varchar query result to a memo field, I can also make it a memo field in the client dataset. I think that is probably the best way forward.

    – GolezTrol
    Mar 28 at 10:49











  • if replacing ado with different dac isn't an option check its internals to see whether it is possible to implement field type mapping feature there

    – vavan
    Mar 29 at 13:22
















Interesting, especially the option to control the internal string field layout. I was hoping that was possible in TClientDataSet as well, but it seems not, but indeed, if I can find a good way to map a char or varchar query result to a memo field, I can also make it a memo field in the client dataset. I think that is probably the best way forward.

– GolezTrol
Mar 28 at 10:49





Interesting, especially the option to control the internal string field layout. I was hoping that was possible in TClientDataSet as well, but it seems not, but indeed, if I can find a good way to map a char or varchar query result to a memo field, I can also make it a memo field in the client dataset. I think that is probably the best way forward.

– GolezTrol
Mar 28 at 10:49













if replacing ado with different dac isn't an option check its internals to see whether it is possible to implement field type mapping feature there

– vavan
Mar 29 at 13:22





if replacing ado with different dac isn't an option check its internals to see whether it is possible to implement field type mapping feature there

– vavan
Mar 29 at 13:22

















draft saved

draft discarded
















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55375774%2ftclientdataset-uses-too-much-memory-for-string-fields%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Kamusi Yaliyomo Aina za kamusi | Muundo wa kamusi | Faida za kamusi | Dhima ya picha katika kamusi | Marejeo | Tazama pia | Viungo vya nje | UrambazajiKuhusu kamusiGo-SwahiliWiki-KamusiKamusi ya Kiswahili na Kiingerezakuihariri na kuongeza habari

Swift 4 - func physicsWorld not invoked on collision? The Next CEO of Stack OverflowHow to call Objective-C code from Swift#ifdef replacement in the Swift language@selector() in Swift?#pragma mark in Swift?Swift for loop: for index, element in array?dispatch_after - GCD in Swift?Swift Beta performance: sorting arraysSplit a String into an array in Swift?The use of Swift 3 @objc inference in Swift 4 mode is deprecated?How to optimize UITableViewCell, because my UITableView lags

Access current req object everywhere in Node.js ExpressWhy are global variables considered bad practice? (node.js)Using req & res across functionsHow do I get the path to the current script with Node.js?What is Node.js' Connect, Express and “middleware”?Node.js w/ express error handling in callbackHow to access the GET parameters after “?” in Express?Modify Node.js req object parametersAccess “app” variable inside of ExpressJS/ConnectJS middleware?Node.js Express app - request objectAngular Http Module considered middleware?Session variables in ExpressJSAdd properties to the req object in expressjs with Typescript