Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of explained plan in XML format #223

Open
wants to merge 19 commits into
base: master
Choose a base branch
from

Conversation

livius2
Copy link

@livius2 livius2 commented Sep 5, 2019

I forgot about this patch creaded few years ago.
I have modified it slightly and i it migrated from svn to git.

It implement explained plan in format XML.
To test it add e.g in trace option
explain_plan_xml=true

It was discussed previously and need some addoption, but to not forgot about i post this pull request as it will be also simplier to modify something.

PS> if someone can point me how to retrive specified value of e.g. ROWS 5 in plan printing in FirstRowsStream.cpp then i can add more infos probably in other places too.
I mean that i need to know this "5" number.
finded self

PS2>make_icu, make_boot, make_all without errors, i do not know why below continuous-integration/travis-ci/pr failed somehow

liviuslivius@poczta.onet.pl added 3 commits September 5, 2019 09:58
@asfernandes
Copy link
Member

I think a machine readable plan would be very good, but much better in json than xml.

@livius2
Copy link
Author

livius2 commented Sep 5, 2019

I can add json format too if needed.

PS. User after connected to db need to choose prefered format presented in e.g. MON$STATEMENTS.
Can you point me how can i add some session (connection or transaction) switch to allow choice about plan format? Is there already some switches too look at?

EDIT

Can i use config same as is for set time zone bind native?
But how to do this only for current transaction?
I think about tool where user can set default settings for connection but tool itself use only one specified format and that tool start custom transaction and can set custom settings for that.

@AppVeyorBot
Copy link

Build firebird 1.0.946 failed (commit 8d6bb0d0ff by @)

@aafemt
Copy link
Contributor

aafemt commented Sep 9, 2019

I don't see writing of XML header. Is resulting XML valid from standard point of view? I'e does it pass validation at https://www.w3schools.com/xml/xml_validator.asp for example? Is the result still valid for non-ascii object names?

@livius2
Copy link
Author

livius2 commented Sep 9, 2019

It is valid, e.g. Postgress also do not show header
But i do not know what to add here utf8?
<?xml version="1.0" encoding="UTF-8"?>

@AppVeyorBot
Copy link

Build firebird 1.0.959 failed (commit 948afa1b92 by @)

@aafemt
Copy link
Contributor

aafemt commented Sep 9, 2019 via email

@livius2
Copy link
Author

livius2 commented Sep 9, 2019

Yes, UTF-8 seems to be the only option given that table names are kept in it. But you also must ensure that XML plan is not converted to connection charset during delivery to client.

I did not analysed this because we have currently explained lagacy plan. I supposed this problem was solved somehow (or simply ignored).

BTW, did you check that it works with something like this: "select ... from "" """""?

good catch :)
It will not cause problem on Firebird side but xml will not be a valid from client POV.
I need escape names here.

@livius2
Copy link
Author

livius2 commented Sep 9, 2019

added header of xml and also escape

example for (with escape for alias):
SELECT * FROM RDB$DATABASE "<xml>" INNER JOIN RDB$RELATIONS R ON "<xml>".RDB$RELATION_ID = R.RDB$RELATION_ID

<?xml version="1.0" encoding="UTF-8"?> 
<Select_Expression xmlns="http://www.firebirdsql.org"> 
	<Node Operation="Nested Loop Join" JoinType="Inner"> 
			<Table alias="&lt;xml&gt;">RDB$DATABASE</Table> 
			<Node Operation="Full Scan"> 
			</Node> 
		<Node Operation="Filter"> 
			<Table Alias="R" Access="By ID">RDB$RELATIONS</Table> 
			<Node Operation="Bitmap"> 
				<Index>RDB$INDEX_1</Index> 
				<Scan>Range</Scan> 
				<Match>full</Match> 
			</Node> 
		</Node> 
	</Node> 
</Select_Expression>

@livius2
Copy link
Author

livius2 commented Sep 10, 2019

I think a machine readable plan would be very good, but much better in json than xml.

I see that JSON is harder to addapt in the current code then XML or YAML. JSON have separator between elements ,
And in every place before print i must know if i must put comma or not.

@@ -448,7 +449,7 @@ interface Statement : ReferenceCounted
uint itemsLength, const uchar* items,
uint bufferLength, uchar* buffer);
uint getType(Status status);
const string getPlan(Status status, boolean detailed);
const string getPlan(Status status, isc_info_sql_plan_format plan_format);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The build is failed because of this line:

/home/appveyor/projects/firebird/gen/Release/cloop/release/bin/cloop /home/appveyor/projects/firebird/src/include/firebird/FirebirdInterface.idl pascal /home/appveyor/projects/firebird/src/include/gen/Firebird.pas Firebird --uses SysUtils
--interfaceFile /home/appveyor/projects/firebird/src/misc/pascal/Pascal.interface.pas
--implementationFile /home/appveyor/projects/firebird/src/misc/pascal/Pascal.implementation.pas
--exceptionClass FbException
--functionsFile /home/appveyor/projects/firebird/temp/Release/func.pas
--prefix I
/home/appveyor/projects/firebird/src/include/firebird/FirebirdInterface.idl:452:38: error: Interface/struct 'isc_info_sql_plan_format' not found.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I not mistaken, you have to add isc_info_sql_plan_format definition into /src/misc/pascal/Pascal.interface.pas

Also, I'm not sure it is legal to change interface method declaration, you should add new method instead.

@AlexPeshkoff
Copy link
Member

AlexPeshkoff commented Sep 10, 2019 via email

@AlexPeshkoff
Copy link
Member

AlexPeshkoff commented Sep 10, 2019 via email

@livius2
Copy link
Author

livius2 commented Sep 10, 2019 via email

@aafemt
Copy link
Contributor

aafemt commented Sep 10, 2019

Absolutely illegal - did not pay attention first.

Isn't it fine as long as size of parameter isn't changed and only value range is expanded in compatible way? Boolean is one byte anyway.

@livius2
Copy link
Author

livius2 commented Sep 10, 2019 via email

@AlexPeshkoff
Copy link
Member

AlexPeshkoff commented Sep 10, 2019 via email

@aafemt
Copy link
Contributor

aafemt commented Sep 10, 2019 via email

@hvlad
Copy link
Member

hvlad commented Sep 10, 2019

Absolutely illegal - did not pay attention first.

Isn't it fine as long as size of parameter isn't changed and only value range is expanded in compatible way? Boolean is one byte anyway.

No, it is not fine.
Data type change == declaration change == contract change == interface change == illegal

@livius2
Copy link
Author

livius2 commented Sep 10, 2019 via email

@hvlad
Copy link
Member

hvlad commented Sep 11, 2019

From user POV declaration is not changed.

It is changed

If someone do not retrive new "header" with new interface "version" than all interface functions still working without change needed.

But if someone ask new functionality using old implementation - he will be badly surprised, at least.

Then interface is not broken and is still compatybile.

Not completely true.

But you decide. I will adapt somehow (if i only know how to change something). Is this final decision?

Add new method to the interface and mark it as new version, for example:

interface Statement : ReferenceCounted
{
...
version:  // 3.0 -> 4.0
  const string getPlanXml(Status status);
}

@@ -1218,6 +1219,7 @@ interface TraceSQLStatement : TraceStatement
TraceParams getInputs();
const string getTextUTF8();
const string getExplainedPlan();
const string getExplainedPlanXml();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be marked as new version, add lable version: before the new method

@livius2
Copy link
Author

livius2 commented Sep 11, 2019

Add new method to the interface and mark it as new version, for example:

interface Statement : ReferenceCounted
{
...
version:  // 3.0 -> 4.0
  const string getPlanXml(Status status);
}

ok.

but is this only place or i must revert change also in e.g.
StatementMetadata::getPlan(isc_info_sql_plan_format plan_format)
and i should add getPlanXml there

And is this supported to have oveloaded functions in above interface? If yes, maybe better choice?

const string getPlan(Status status, boolean detailed);
const string getPlan(Status status, isc_info_sql_plan_format plan_format);

My knowledge about C++ is strongly limited here.

@hvlad
Copy link
Member

hvlad commented Sep 11, 2019

but is this only place or i must revert change also in e.g.
StatementMetadata::getPlan(isc_info_sql_plan_format plan_format)
and i should add getPlanXml there

Yes. Revert change (interface method declaration should never be changed!) and add new method.

And is this supported to have oveloaded functions in above interface? If yes, maybe better choice?

Please, don't add confusion, use different method name.
As you already did with TraceSQLStatementImpl, btw :)

@aafemt
Copy link
Contributor

aafemt commented Sep 11, 2019 via email

@livius2
Copy link
Author

livius2 commented Sep 11, 2019

Yes. Revert change (interface method declaration should never be changed!) and add new method.
But rather than getPlanXml I would prefer getPlanEx with choice of format. It is easier to expand later if needed.

Good concept for me. All already existing getPlan(bool explained) will simply call one method with appropriate parameter.
But name maybe getPlanInFormat?

@dyemanov
Copy link
Member

But name maybe getPlanInFormat?

getFormattedPlan() maybe?

@hvlad
Copy link
Member

hvlad commented Sep 11, 2019

But name maybe getPlanInFormat?

getFormattedPlan() maybe?

getPlanEx is better for me, but definitely not getPlanInFormat :)

@livius2
Copy link
Author

livius2 commented Sep 11, 2019

I suppose i have fixed all problems reported.
I have used name getFormattedPlan if needed i can change it to something else getPlanFormatted, getPlanEx ...

I think about introducing new SET command to choose plan stored in MON$STATEMENTS. Or is there a better way?

PS> it looks like "continuous-integration" is now ok

@AppVeyorBot
Copy link

Build firebird 1.0.962 completed (commit 02aa1f8427 by @)

liviuslivius@poczta.onet.pl added 5 commits September 11, 2019 15:52
Information of First and Skip values.

e.g. SELECT FIRST 5 SKIP 2 * FROM RDB$RELATIONS
we will see
limitRows=5 skipRows=2
Only TYPE_LITERAL nodes are accepted.
Any other can contain subquery e.g.
SELECT * FROM RDB$RELATIONS R ROWS (SELECT COUNT(*) FROM RDB$DATABASE)

SELECT * FROM RDB$RELATIONS R ROWS (5-(SELECT COUNT(*) FROM RDB$DATABASE))
@AppVeyorBot
Copy link

Build firebird 1.0.988 completed (commit 7486e4e5c5 by @)

liviuslivius@poczta.onet.pl added 2 commits September 19, 2019 08:24
… plan

store statistics into plan about:
- memory;
- physical IO global and global per table;
- logical IO global and global per table.
@livius2
Copy link
Author

livius2 commented Sep 20, 2019

store statistics into plan about:

  • memory;
  • physical IO global and global per table;
  • logical IO global and global per table.

Currently can be used to store plan into MON$STATEMENTS with cumulative info during statement execution, runned again get updated statistics.
Slightly related to CORE-6030, but there is need for info about particullar streams.

As still there is no SET command to change format of the plan,
to test it, change format of plan in Monitoring::dumpAttachment from isc_info_sql_plan_format_explain_legacy to isc_info_sql_plan_format_explain_xml.

sample plan:

<?xml version="1.0" encoding="UTF-8"?>
<Statements>
	<Statistics>
		<PhysicalIO>
			<PageReads>54</PageReads>
			<PageWrites>0</PageWrites>
			<PageFetches>7239</PageFetches>
			<PageMarks>0</PageMarks>
		</PhysicalIO>
		<LogicalIO>
			<RecordSeqReads>7022</RecordSeqReads>
			<RecordIdxReads>0</RecordIdxReads>
			<RecordInserts>0</RecordInserts>
			<RecordUpdates>0</RecordUpdates>
			<RecordDeletes>0</RecordDeletes>
			<RecordBackouts>0</RecordBackouts>
			<RecordPurges>0</RecordPurges>
			<RecordExpurges>0</RecordExpurges>
			<RecordLocks>0</RecordLocks>
			<RecordWaits>0</RecordWaits>
			<RecordConflicts>0</RecordConflicts>
			<RecordBackversionReads>0</RecordBackversionReads>
			<RecordFragmentReads>0</RecordFragmentReads>
			<RecordRptReads>0</RecordRptReads>
			<RecordImgc>0</RecordImgc>
		</LogicalIO>
		<TableStats>
			<Table name="WPLATA">
				<LogicalIO>
					<LogicalIO>
						<RecordSeqReads>7022</RecordSeqReads>
						<RecordIdxReads>0</RecordIdxReads>
						<RecordInserts>0</RecordInserts>
						<RecordUpdates>0</RecordUpdates>
						<RecordDeletes>0</RecordDeletes>
						<RecordBackouts>0</RecordBackouts>
						<RecordPurges>0</RecordPurges>
						<RecordExpurges>0</RecordExpurges>
						<RecordLocks>0</RecordLocks>
						<RecordWaits>0</RecordWaits>
						<RecordConflicts>0</RecordConflicts>
						<RecordBackversionReads>0</RecordBackversionReads>
						<RecordFragmentReads>0</RecordFragmentReads>
						<RecordRptReads>0</RecordRptReads>
						<RecordImgc>0</RecordImgc>
					</LogicalIO>
				</LogicalIO>
			</Table>
		</TableStats>
	</Statistics>
	<Statement xmlns="https://www.firebirdsql.org/2019/ExecutionPlan">
		<Node operation="First N Records" limitRows="10000">
			<Node operation="Full Scan">
			<Table alias="WPLATA">WPLATA</Table>
			</Node>
		</Node>
	</Statement>
</Statements>

@AppVeyorBot
Copy link

Build firebird 1.0.1009 completed (commit 38e61cea5e by @)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants