Avoid superfluous dictionaries load (system.tables, SHOW CREATE TABLE)

This patch avoids loading dictionaries for:
- SELECT * FROM system.tables (used by clickhouse-client for completion)
- SHOW CREATE TABLE some_dict

But the dictionary will still be loaded on:
- SHOW CREATE TABLE some_dict (from the database with Dictionary engine)
This commit is contained in:
Azat Khuzhin 2020-04-10 01:32:59 +03:00
parent e0c972448e
commit 55a143d1a5
6 changed files with 94 additions and 10 deletions

View File

@ -64,7 +64,7 @@ StoragePtr DatabaseDictionary::tryGetTable(
const Context & context,
const String & table_name) const
{
auto dict_ptr = context.getExternalDictionariesLoader().tryGetDictionary(table_name);
auto dict_ptr = context.getExternalDictionariesLoader().tryGetDictionary(table_name, true /*load*/);
if (dict_ptr)
{
const DictionaryStructure & dictionary_structure = dict_ptr->getStructure();
@ -94,7 +94,7 @@ ASTPtr DatabaseDictionary::getCreateTableQueryImpl(const Context & context,
const auto & dictionaries = context.getExternalDictionariesLoader();
auto dictionary = throw_on_error ? dictionaries.getDictionary(table_name)
: dictionaries.tryGetDictionary(table_name);
: dictionaries.tryGetDictionary(table_name, true /*load*/);
if (!dictionary)
return {};

View File

@ -26,6 +26,8 @@ namespace ErrorCodes
extern const int TABLE_ALREADY_EXISTS;
extern const int UNKNOWN_TABLE;
extern const int DICTIONARY_ALREADY_EXISTS;
extern const int FILE_DOESNT_EXIST;
extern const int CANNOT_GET_CREATE_TABLE_QUERY;
}
@ -165,7 +167,7 @@ void DatabaseWithDictionaries::removeDictionary(const Context & context, const S
}
}
StoragePtr DatabaseWithDictionaries::tryGetTable(const Context & context, const String & table_name) const
StoragePtr DatabaseWithDictionaries::tryGetTableImpl(const Context & context, const String & table_name, bool load) const
{
if (auto table_ptr = DatabaseWithOwnTablesBase::tryGetTable(context, table_name))
return table_ptr;
@ -173,10 +175,34 @@ StoragePtr DatabaseWithDictionaries::tryGetTable(const Context & context, const
if (isDictionaryExist(context, table_name))
/// We don't need lock database here, because database doesn't store dictionary itself
/// just metadata
return getDictionaryStorage(context, table_name);
return getDictionaryStorage(context, table_name, load);
return {};
}
StoragePtr DatabaseWithDictionaries::tryGetTable(const Context & context, const String & table_name) const
{
return tryGetTableImpl(context, table_name, true /*load*/);
}
ASTPtr DatabaseWithDictionaries::getCreateTableQueryImpl(const Context & context, const String & table_name, bool throw_on_error) const
{
ASTPtr ast;
bool has_table = tryGetTableImpl(context, table_name, false /*load*/) != nullptr;
auto table_metadata_path = getObjectMetadataPath(table_name);
try
{
ast = getCreateQueryFromMetadata(context, table_metadata_path, throw_on_error);
}
catch (const Exception & e)
{
if (!has_table && e.code() == ErrorCodes::FILE_DOESNT_EXIST && throw_on_error)
throw Exception{"Table " + backQuote(table_name) + " doesn't exist",
ErrorCodes::CANNOT_GET_CREATE_TABLE_QUERY};
else if (throw_on_error)
throw;
}
return ast;
}
DatabaseTablesIteratorPtr DatabaseWithDictionaries::getTablesWithDictionaryTablesIterator(
const Context & context, const FilterByNameFunction & filter_by_dictionary_name)
@ -195,7 +221,7 @@ DatabaseTablesIteratorPtr DatabaseWithDictionaries::getTablesWithDictionaryTable
while (dictionaries_it && dictionaries_it->isValid())
{
auto table_name = dictionaries_it->name();
auto table_ptr = getDictionaryStorage(context, table_name);
auto table_ptr = getDictionaryStorage(context, table_name, false /*load*/);
if (table_ptr)
result.emplace(table_name, table_ptr);
dictionaries_it->next();
@ -223,11 +249,11 @@ bool DatabaseWithDictionaries::isDictionaryExist(const Context & /*context*/, co
return dictionaries.find(dictionary_name) != dictionaries.end();
}
StoragePtr DatabaseWithDictionaries::getDictionaryStorage(const Context & context, const String & table_name) const
StoragePtr DatabaseWithDictionaries::getDictionaryStorage(const Context & context, const String & table_name, bool load) const
{
auto dict_name = database_name + "." + table_name;
const auto & external_loader = context.getExternalDictionariesLoader();
auto dict_ptr = external_loader.tryGetDictionary(dict_name);
auto dict_ptr = external_loader.tryGetDictionary(dict_name, load);
if (dict_ptr)
{
const DictionaryStructure & dictionary_structure = dict_ptr->getStructure();

View File

@ -20,6 +20,8 @@ public:
StoragePtr tryGetTable(const Context & context, const String & table_name) const override;
ASTPtr getCreateTableQueryImpl(const Context & context, const String & table_name, bool throw_on_error) const override;
DatabaseTablesIteratorPtr getTablesWithDictionaryTablesIterator(const Context & context, const FilterByNameFunction & filter_by_dictionary_name) override;
DatabaseDictionariesIteratorPtr getDictionariesIterator(const Context & context, const FilterByNameFunction & filter_by_dictionary_name) override;
@ -37,7 +39,7 @@ protected:
void attachToExternalDictionariesLoader(Context & context);
void detachFromExternalDictionariesLoader();
StoragePtr getDictionaryStorage(const Context & context, const String & table_name) const;
StoragePtr getDictionaryStorage(const Context & context, const String & table_name, bool load) const;
ASTPtr getCreateDictionaryQueryImpl(const Context & context,
const String & dictionary_name,
@ -45,6 +47,8 @@ protected:
private:
ext::scope_guard database_as_config_repo_for_external_loader;
StoragePtr tryGetTableImpl(const Context & context, const String & table_name, bool load) const;
};
}

View File

@ -23,9 +23,12 @@ public:
return std::static_pointer_cast<const IDictionaryBase>(load(name));
}
DictPtr tryGetDictionary(const std::string & name) const
DictPtr tryGetDictionary(const std::string & name, bool load) const
{
if (load)
return std::static_pointer_cast<const IDictionaryBase>(tryLoad(name));
else
return std::static_pointer_cast<const IDictionaryBase>(getCurrentLoadResult(name).object);
}
static void resetAll();

View File

@ -0,0 +1,19 @@
NOT_LOADED
NOT_LOADED
CREATE DICTIONARY dict_db_01224.dict
(
`key` UInt64 DEFAULT 0,
`val` UInt64 DEFAULT 10
)
PRIMARY KEY key
SOURCE(CLICKHOUSE(HOST 'localhost' PORT 9000 USER 'default' TABLE 'dict_data' PASSWORD '' DB 'dict_db_01224'))
LIFETIME(MIN 0 MAX 0)
LAYOUT(FLAT())
NOT_LOADED
CREATE TABLE dict_db_01224_dictionary.`dict_db_01224.dict`
(
`key` UInt64,
`val` UInt64
)
ENGINE = Dictionary(`dict_db_01224.dict`)
LOADED

View File

@ -0,0 +1,32 @@
DROP DATABASE IF EXISTS dict_db_01224;
DROP DATABASE IF EXISTS dict_db_01224_dictionary;
CREATE DATABASE dict_db_01224;
CREATE TABLE dict_db_01224.dict_data (key UInt64, val UInt64) Engine=Memory();
CREATE DICTIONARY dict_db_01224.dict
(
key UInt64 DEFAULT 0,
val UInt64 DEFAULT 10
)
PRIMARY KEY key
SOURCE(CLICKHOUSE(HOST 'localhost' PORT 9000 USER 'default' TABLE 'dict_data' PASSWORD '' DB 'dict_db_01224'))
LIFETIME(MIN 0 MAX 0)
LAYOUT(FLAT());
SELECT status FROM system.dictionaries WHERE database = 'dict_db_01224' AND name = 'dict';
SELECT * FROM system.tables FORMAT Null;
SELECT status FROM system.dictionaries WHERE database = 'dict_db_01224' AND name = 'dict';
SHOW CREATE TABLE dict_db_01224.dict FORMAT TSVRaw;
SELECT status FROM system.dictionaries WHERE database = 'dict_db_01224' AND name = 'dict';
CREATE DATABASE dict_db_01224_dictionary Engine=Dictionary;
SHOW CREATE TABLE dict_db_01224_dictionary.`dict_db_01224.dict` FORMAT TSVRaw;
SELECT status FROM system.dictionaries WHERE database = 'dict_db_01224' AND name = 'dict';
DROP DICTIONARY dict_db_01224.dict;
SELECT status FROM system.dictionaries WHERE database = 'dict_db_01224' AND name = 'dict';
DROP DATABASE dict_db_01224;
DROP DATABASE dict_db_01224_dictionary;