Skip to content

Conversation

Enmk
Copy link
Contributor

@Enmk Enmk commented Mar 23, 2020

Implemented LowCardinality(String) and LowCardinality(FixedString) with native binary serialization and a multitude of tests.

To enable efficient LowCardinality implementation, added some methods to the Column interface (and implementation in most derived classes), and added ItemView class (see the documentation in sources).

Also, to enable receiving LC columns from the server, updated client TCP protocol revision to 54405 (DBMS_MIN_REVISION_WITH_LOW_CARDINALITY_TYPE). That also forced me to update client/server protocol a bit:

  • read server display string and version patch
  • send client version patch
  • fix parsing of DateTime type with timezone

Known limitations:

  • LowCardniality of Nullable is not supported.

Enmk added 11 commits March 23, 2020 17:59
Minor refactoing of columns_ut.cpp: moved timers to utils.h

Basic support of LowCardinality column, with draft serialization.

LowCardinality implementation

LowCardinality fixes:

Fixed ColumnLowCardinality::Load to update unique items map
Updated ColumnLowCardinality::Swap to validate nested type of other
column.

Minor fix: moved line around

Tests for ColumnLowCardinality

moved performance-tests to performance_tests.cpp
Added performance test for ColumnLowCardinality(String) and ColumnLowCardinality(FixedString)
Added type parser unit-tests for LowCardinality
Added client tests for LowCardinality

Bumped revision up to indicate that LowCardinality is supported

DUMP of current work

Implemented ItemView struct, using it as return type of Column::GetItem()
Fixed various bugs in ColumnLowCardinality: mostly serialization and deserialization-wise
More tests, for LowCardinaility in isolation, unit tests, performance
tests, integration tests.

Fixed, updated and cleaned up test cases
Moved ItemView to separate header
Renamed ColumnLowCardinalityWrapper and renamed it into ColumnLowCardinalityT
Udpdated tests accordingly
@Enmk Enmk requested a review from traceon March 23, 2020 20:22
@Enmk
Copy link
Contributor Author

Enmk commented Mar 24, 2020

Comparison of populating, inserting and selecting 1'000'000 items performance-wise:

UInt64 String FixedString(8) LowCardinality(String) LowCardinality(FixedString(8))
Appending 10186 16580 9503 136121 129960
INSERT 1465 20953 1495 922 964
SELECT 434942 473523 448177 514830 553979
Dictionary size: 118 116

Please note:

  • same 8-byte strings were used for both FixedString(8) and LowCardinaility(FixedString(8))
  • same 7-byte strings were used for both String and LowCardinaility(String)
  • dictionary size reflects number of unique items + 1 extra NULL-item which is an implementation detail.

Since it is not present in older versions of XCode
@Enmk Enmk force-pushed the low-cardinality branch from 33b3f04 to 3c51f41 Compare March 24, 2020 12:00
Since there is no clickhouse server for MacOS started
Copy link
Contributor

@traceon traceon left a comment

Choose a reason for hiding this comment

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

First bunch of comments. Still in progress.

Enmk added 2 commits March 24, 2020 22:25
 * client_version_patch in ClientInfo
 * every overload of Column::Swap() now throws an exception on attempt to swap with instance of wrong type.
 * ColumnNullable::Swap() throws is nested column is of unexpected type.
 * PausableTimer is now started in paused mode.
 * few whitespace changes here and there
@Enmk
Copy link
Contributor Author

Enmk commented Mar 24, 2020

Updated and fixed all mentioned issues + fixed inconsistent whitespace (at least in code added/updated in this PR)

Copy link
Contributor

@traceon traceon left a comment

Choose a reason for hiding this comment

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

Could you please also revisit and review the Timers code and make it solid and bulletproof and impossible to misuse, as it is arguably the most important code in this PR :) since it measures the performance of a feature whose sole existence is based on the performance benefits it gives.

// however some day they may.

// prefix
uint64_t key_version;
Copy link
Contributor

Choose a reason for hiding this comment

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

Unless it is a conscious performance-motivated decision backed by data, vars are better to always be initialized. (Here and several other places.)

return;

dictionary_column_->Swap(*col->dictionary_column_);
index_column_.swap(col->index_column_);
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this be index_column_->Swap(*col->index_column_); too?

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 matter here, but for consistency, let’s update it.


timer.Start();
column.Save(&ostr);
ostr.Flush();
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you really want to measure flush too?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, since lots of interesting things can happen there, also I am measuring the whole process, the way it is in real cases.

Copy link
Contributor

Choose a reason for hiding this comment

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

OK, however potentially LowCardinality + flush, and regular type + flush numbers may differ insignificantly, if flush is heavy. While isolated LowCardinality may be like several times slower than a regular type, and that difference just dwarfed by flush overhead.

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 is quite the opposite: serialization/deserialization of LowCardinality columns is MUCH faster (up to 100 times faster than bare String and up to 3 times faster than bare FixedSring columns)

Copy link
Contributor

@traceon traceon Mar 25, 2020

Choose a reason for hiding this comment

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

Yes, sorry, my bad. But the idea remains the same, the observer wont be able to properly see that degree of difference.

Enmk added 4 commits March 25, 2020 11:21
 * Using simpler timer
 * More clean measurments of SELECT
 * minor whitespace/braces fixes
…m ColumnLowCardinality

+ Other minor fixes: mostly whitespace.
@Enmk
Copy link
Contributor Author

Enmk commented Mar 25, 2020

After the most recent update to implementation and measurements:

UInt64 String FixedString(8) LowCardinality(String) LowCardinality(FixedString(8))
Append 10452 17879 10984 60052 61923
INSERT 1418 22340 1409 732 736
SELECT 4432 25419 2090 459 545

Tested against localhost server, so the IO lag is diminishable. Tested on 1M entries, time is in microseconds.

@traceon
Copy link
Contributor

traceon commented Mar 25, 2020

LGTM

@traceon traceon merged commit ad5fd98 into ClickHouse:master Mar 25, 2020
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.

2 participants