Oto poprawiona wersja tekstu w języku angielskim:
Hi,
I'm not sure about the use case, as retrieving 1 million rows is an unusual operation. Is it a frequent task? Why do you consider 12 seconds to be slow? Please describe the scenario.
However, if you're working directly on the server, you can use XNet or the embedded mode, which should be faster.
On 22.05.2025 at 04:08, 'Hamish Moffatt' via firebird-support wrote:
I have a table (in Firebird 5.0.2) which is simply a pair of INTEGER columns, with a primary key across both. I need to read the whole table out, and there's 1.3 million records, and this is slow - it's taking over 12 seconds on a reasonably fast PCHow do you connect to your database? Via TCP/IP, XNET, or in embedded mode?
The issue seems to be just the number of calls to isc_dsql_fetch and the logic to unpack the structures. I'm using Qt and its built-in driver for Firebird.
The server is running on the same machine. I fiddled with TcpRemoteBufferSize and Wirecrypt settings and didn't see any change there.
Is there any way to speed this up?
If the speed of fetching data is a crucial factor, use embedded mode - this way all DB access code lives in your process' space and all data transfer boils down to copying memory blocks.
If you need to go through the actual server process, try XNET - https://github.com/FirebirdSQL/firebird/blob/master/doc/README.xnet.
I do need to use the server, as I have other applications connecting too. In production my application server runs in a different container to Firebird, so it will have to be TCP.
I did try XNET in my development environment just for interest's sake. Fetching all those rows was slightly faster, but not significantly. Possibly within the noise.
Interestingly when I force quit my application, the server logged

HAMISH-WIN10
Thu May 22 20:33:35 2025
XNET error: Server shutdown detected


then connecting to it over XNET again hangs. And one time I got
HAMISH-WIN10 Thu May 22 19:44:48 2025
XNET error: XNET server initialization failed. Probably
another instance of server is already running.
operating system directive CreateMutex failed
Cannot create a file when that file already exists.
Hamish
The plan shows the select is using the primary key. There's no where
clause.
The plan shows the select is using the primary key. There's no where
clause.
ORDER BY PK ?
Yes.
SQL> set planonly ;
SQL> select course_num,class_num from g_course_class order by
1,2 ;
PLAN (G_COURSE_CLASS ORDER PK_G_COURSE_CLASS)
Hamish
On 23/05/2025 03:48, 'Hamish Moffatt' via firebird-support wrote:
On 22/5/25 12:08, 'Hamish Moffatt' via firebird-support wrote:
Crazy ideas include a stored proc or user function that returns as many rows as possible packed into one, in JSON format, or a string list or something. (or an ARRAY but that seems to be discouraged.)
I gave this a try - a stored proc returning an INTEGER and a BLOB text blob containing a JSON list of numbers - and it was slower - 11 seconds grew to 20.
For a single row, or for multiple rows? How did you generate the blob?
The table links each COURSE_NUM to a list of CLASS_NUM, so I return a row for each COURSE_NUM with a JSON array of CLASS_NUM integers.
COURSE_NUM INTEGER Not Null
CLASS_NUM INTEGER Not Null DEFAULT 1
CONSTRAINT FK_G_COURSE_CLASS_CLASS:
Foreign key (CLASS_NUM) References G_CLASS (CLASS_NUM) On
Update Cascade On Delete Cascade
CONSTRAINT FK_G_COURSE_CLASS_TEST:
Foreign key (COURSE_NUM) References G_COURSE (COURSE_NUM) On
Update Cascade On Delete Cascade
CONSTRAINT PK_G_COURSE_CLASS:
Primary key (COURSE_NUM, CLASS_NUM)

Procedure
text:
Hamish
SQL> set planonly ;
SQL> select course_num,class_num from g_course_class order by 1,2 ;
PLAN (G_COURSE_CLASS ORDER PK_G_COURSE_CLASS)
Could you try without ORDER BY - to check if it is a reason of the slowness ?Or, if it is absolute necessary, try to force sort:
select course_num + 0, class_num from g_course_class order by 1,2 ;
Yes, those are a bit faster. Testing from Python,

select
COURSE_NUM, CLASS_NUM from G_COURSE_CLASS order by COURSE_NUM,
CLASS_NUM - 12 seconds
select COURSE_NUM, CLASS_NUM from G_COURSE_CLASS - 9 seconds
select
COURSE_NUM+0, CLASS_NUM from G_COURSE_CLASS order by 1, 2 - 10.2
seconds
My server version here is 5.0.1.
Hamish
Tried with IBE, connect using INET (localhost), table with two INTEGER fields, 1'300'000 records:
Thanks, I can also reproduce this in IBExpert, though my table has a primary key over both values, and both are also foreign keys.
CREATE TABLE G_COURSE_CLASS (
COURSE_NUM INTEGER NOT NULL,
CLASS_NUM INTEGER DEFAULT 1 NOT NULL,
CONSTRAINT PK_G_COURSE_CLASS PRIMARY KEY (COURSE_NUM,
CLASS_NUM),
CONSTRAINT FK_G_COURSE_CLASS_TEST FOREIGN KEY (COURSE_NUM)
REFERENCES G_COURSE (COURSE_NUM) ON DELETE CASCADE ON UPDATE
CASCADE,
CONSTRAINT FK_G_COURSE_CLASS_CLASS FOREIGN KEY (CLASS_NUM)
REFERENCES G_CLASS (CLASS_NUM) ON DELETE CASCADE ON UPDATE CASCADE
);
select
course_num, class_num
from g_course_class
PLAN (G_COURSE_CLASS NATURAL)
Execute time = 3s 641ms
select course_num+0, class_num
from g_course_class order by 1, 2
PLAN SORT (G_COURSE_CLASS NATURAL)
Execute time = 4s 500ms
select course_num, class_num
from g_course_class order by 1, 2
PLAN (G_COURSE_CLASS ORDER PK_G_COURSE_CLASS)
Execute time = 11s 563ms
Why is it much slower to use the primary key for the sort?
Looks like problem with client app (python ?), not with Firebird.One of the obvious suspect is how memory for resultset is allocated.
I did the quick benchmarking in Python using fdb, and is much
slower than the above.
My application is in Qt (C++). I made the query change above and
I see it is much faster now from my C++ application, down from 12
seconds to 5.4.
Thanks,
Hamish