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

Perf: Change SqlParameter bool fields to flags #1064

Merged
merged 2 commits into from
Jun 14, 2021

Conversation

Wraith2
Copy link
Contributor

@Wraith2 Wraith2 commented May 7, 2021

This ports the second part of the changes from In dotnet/corefx#35549 , it replaces many individual boolean fields with bitflags to reduce the size of each instance. I've used masking not Enum.HasFlag because it is portable over netcore and netfx as pointed out by @cmeyertons in #1054

Using ObjectInspector mockups (replaced real ref types with object which are same size), gives a reduction from 152 to 136, a 10% size reduction.

Type layout for 'OldSqlParameter'
Size: 152 bytes. Paddings: 7 bytes (%4 of empty space)
|=====================================================================|
| Object Header (8 bytes)                                             |
|---------------------------------------------------------------------|
| Method Table Ptr (8 bytes)                                          |
|=====================================================================|
|   0-7: Object _metaType (8 bytes)                                   |
|---------------------------------------------------------------------|
|  8-15: Object _collation (8 bytes)                                  |
|---------------------------------------------------------------------|
| 16-23: Object _xmlSchemaCollection (8 bytes)                        |
|---------------------------------------------------------------------|
| 24-31: String _udtTypeName (8 bytes)                                |
|---------------------------------------------------------------------|
| 32-39: String _typeName (8 bytes)                                   |
|---------------------------------------------------------------------|
| 40-47: Exception _udtLoadError (8 bytes)                            |
|---------------------------------------------------------------------|
| 48-55: String _parameterName (8 bytes)                              |
|---------------------------------------------------------------------|
| 56-63: Object _internalMetaType (8 bytes)                           |
|---------------------------------------------------------------------|
| 64-71: Object _sqlBufferReturnValue (8 bytes)                       |
|---------------------------------------------------------------------|
| 72-79: Object _valueAsINullable (8 bytes)                           |
|---------------------------------------------------------------------|
| 80-87: Object _value (8 bytes)                                      |
|---------------------------------------------------------------------|
| 88-95: Object _coercedValue (8 bytes)                               |
|---------------------------------------------------------------------|
| 96-103: Object _parent (8 bytes)                                    |
|---------------------------------------------------------------------|
| 104-111: String _sourceColumn (8 bytes)                             |
|---------------------------------------------------------------------|
| 112-115: Int32 _actualSize (4 bytes)                                |
|---------------------------------------------------------------------|
| 116-119: Int32 _direction (4 bytes)                                 |
|---------------------------------------------------------------------|
| 120-123: Int32 _size (4 bytes)                                      |
|---------------------------------------------------------------------|
| 124-127: Int32 _offset (4 bytes)                                    |
|---------------------------------------------------------------------|
| 128-131: Int32 _sourceVersion (4 bytes)                             |
|---------------------------------------------------------------------|
|   132: Byte _precision (1 byte)                                     |
|---------------------------------------------------------------------|
|   133: Byte _scale (1 byte)                                         |
|---------------------------------------------------------------------|
|   134: Boolean _hasScale (1 byte)                                   |
|---------------------------------------------------------------------|
|   135: Boolean _isSqlParameterSqlType (1 byte)                      |
|---------------------------------------------------------------------|
|   136: Boolean _isNull (1 byte)                                     |
|---------------------------------------------------------------------|
|   137: Boolean _coercedValueIsSqlType (1 byte)                      |
|---------------------------------------------------------------------|
|   138: Boolean _coercedValueIsDataFeed (1 byte)                     |
|---------------------------------------------------------------------|
|   139: Boolean _sourceColumnNullMapping (1 byte)                    |
|---------------------------------------------------------------------|
|   140: Boolean _isNullable (1 byte)                                 |
|---------------------------------------------------------------------|
|   141: Boolean <HasRecievedMetadata>k__BackingField (1 byte)        |
|---------------------------------------------------------------------|
|   142: Boolean <ForceColumnEncryption>k__BackingField (1 byte)      |
|---------------------------------------------------------------------|
|   143: Boolean <SourceColumnNullMapping>k__BackingField (1 byte)    |
|---------------------------------------------------------------------|
|   144: Boolean <IsDerivedParameterTypeName>k__BackingField (1 byte) |
|---------------------------------------------------------------------|
| 145-151: padding (7 bytes)                                          |
|=====================================================================|


Type layout for 'NewSqlParameter'
Size: 136 bytes. Paddings: 0 bytes (%0 of empty space)
|===============================================|
| Object Header (8 bytes)                       |
|-----------------------------------------------|
| Method Table Ptr (8 bytes)                    |
|===============================================|
|   0-7: Object _metaType (8 bytes)             |
|-----------------------------------------------|
|  8-15: Object _collation (8 bytes)            |
|-----------------------------------------------|
| 16-23: Object _xmlSchemaCollection (8 bytes)  |
|-----------------------------------------------|
| 24-31: String _udtTypeName (8 bytes)          |
|-----------------------------------------------|
| 32-39: String _typeName (8 bytes)             |
|-----------------------------------------------|
| 40-47: Exception _udtLoadError (8 bytes)      |
|-----------------------------------------------|
| 48-55: String _parameterName (8 bytes)        |
|-----------------------------------------------|
| 56-63: Object _internalMetaType (8 bytes)     |
|-----------------------------------------------|
| 64-71: Object _sqlBufferReturnValue (8 bytes) |
|-----------------------------------------------|
| 72-79: Object _valueAsINullable (8 bytes)     |
|-----------------------------------------------|
| 80-87: Object _value (8 bytes)                |
|-----------------------------------------------|
| 88-95: Object _coercedValue (8 bytes)         |
|-----------------------------------------------|
| 96-103: Object _parent (8 bytes)              |
|-----------------------------------------------|
| 104-111: String _sourceColumn (8 bytes)       |
|-----------------------------------------------|
| 112-115: Int32 _actualSize (4 bytes)          |
|-----------------------------------------------|
| 116-119: Int32 _direction (4 bytes)           |
|-----------------------------------------------|
| 120-123: Int32 _size (4 bytes)                |
|-----------------------------------------------|
| 124-127: Int32 _offset (4 bytes)              |
|-----------------------------------------------|
| 128-131: Int32 _sourceVersion (4 bytes)       |
|-----------------------------------------------|
| 132-133: UInt16 _flags (2 bytes)              |
|-----------------------------------------------|
|   134: Byte _precision (1 byte)               |
|-----------------------------------------------|
|   135: Byte _scale (1 byte)                   |
|===============================================|

Comment on lines 1009 to 1015
SqlParameterFlags.SourceColumnNullMapping |
SqlParameterFlags.IsNull |
SqlParameterFlags.IsNullable |
SqlParameterFlags.IsSqlParameterSqlType |
SqlParameterFlags.CoercedValueIsDataFeed |
SqlParameterFlags.CoercedValueIsSqlType |
SqlParameterFlags.ForceColumnEncryption
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT: Could you add this block to the SqlParameterFlags as a member with a meaningful name?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It doesn't really have a name of it's own, it's just a faster way of copying the individual fields than setting them one at a time. It's only use in this one place so being able to refer to it quickly doesn't seem useful.

Do you have an opinion on whether HasScale and IsDerivedParameterTypeName should be added here?

Copy link
Contributor

Choose a reason for hiding this comment

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

These two are the SqlParameter properties that describe it and they're part of the SqlParameter object characteristic. So, I don't see any reason why they shouldn't be copied to a cloned object!

Any thoughts @David-Engel

Copy link
Contributor

Choose a reason for hiding this comment

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

@Wraith2 Why are all the elements of the SqlParameterFlags enum not included here? I see that HasReceivedMetadata, IsDerivedParameterTypeName, and HasScale are not included. I think that may be what Davoud is really asking. (Or what is special about this subset of items that only they are included?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I asked the question earlier, #1064 (comment) and the answer about why is that because they weren't copied in the original. I think they should be, or at least the two I identified. Doing so is a behavioural change though and I avoid those in these merge PR's and call out when I do make them.

If we all agree that they should be included I can add them. You need to be aware that it might change behaviour though.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, I see. HasScale has comments around it indicating it should be ignored

private bool _hasScale; // V1.0 compat, ignore _hasScale

and that code goes way back in netfx. So I don't care about that one.

But IsDerivedParameterTypeName was recently added in #1020, so I'm good with correcting that here and changing the behavior, assuming it was an oversight there.

HasReceivedMetadata is also relatively new, added for AE in SQL 2016. Looking at how it is used, I'm inclined to leave it as-is. (But I'm not saying it's correct or not.)

Copy link
Contributor

@DavoudEshtehari DavoudEshtehari Jun 11, 2021

Choose a reason for hiding this comment

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

@Wraith2 One reason for wrapping these values in SqlParameterFlags would be drawing special attention to it at the time of adding a new parameter in the future. I believe adding a new member to SqlParameterFlags like Cloneables would clarify it and it doesn't have any downsides.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, done and a comment left to indicate that those were considered so no-one else has to wonder in future.

@DavoudEshtehari DavoudEshtehari removed their assignment Jun 10, 2021
@Wraith2 Wraith2 force-pushed the perf-sqlparamflags branch from 6a4f845 to b8e8c13 Compare June 11, 2021 00:36
@Wraith2
Copy link
Contributor Author

Wraith2 commented Jun 11, 2021

Feedback addressed and rebased to master.

@cheenamalhotra cheenamalhotra added this to the 4.0.0-preview1 milestone Jun 14, 2021
@cheenamalhotra cheenamalhotra merged commit 4c3dcb9 into dotnet:main Jun 14, 2021
@Wraith2 Wraith2 deleted the perf-sqlparamflags branch June 14, 2021 23:14
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.

[Minor optimisation] Potential for optimisation in WriteToServer (SqlMetaDataPriv.IsNullable)
4 participants