Full-Text Search Not working (FREETEXT - CONTAINS) - sql

Freetext not return all of the words from table. And Contains not work
I have a one row wich include in mycolumn="Life of a King"
I tried 2 method;
First "contains"
SELECT * FROM MYTABLE WHERE CONTAINS(MYCOLUMN,'Life NEAR of NEAR a NEAR King')
It returns NOTHING
Second:
SELECT * FROM MYTABLE WHERE FREETEXT(MYCOLUMN,'Life of a King')
It returns 237 rows!
which is ;
"Life of Pie","It's a Wonderfull Life","The Lion King","King Arthur","Life Story","Life of a King" etc...
I want to return row which only include "Life"+"of"+"a"+"King" words together.
Thanks for replies!

I am assuming full text field is nvarchar.
Here is my example:
CREATE TABLE [dbo].[FullTextTable](
[ID] [int] NOT NULL PRIMARY KEY,
[FullTextField] [nvarchar](max) NOT NULL
);
GO
CREATE FULLTEXT INDEX ON FullTextTable([FullTextField])
KEY INDEX [PK_FullTextTable]
WITH STOPLIST = SYSTEM;
GO
Following query returning exact value:
SELECT FullTextField
FROM FullTextTable
WHERE
CONTAINS
(FullTextField, N'"Life NEAR of NEAR a NEAR King"' );
GO

You must consider below points
The column for which you are doing searching should have FULLTEXT INDEX
Check the searching term is exists in the table
SELECT * FROM sys.dm_fts_index_keywords(DB_ID('your_DB_Name'),
OBJECT_ID('_your_table_Name'))
where display_term like '%your_searching_keyword%'
The "Change Tracking" property should be set to "automatic". If after creating index you are going to add or delete rows from the table or data in the table is not static.

Related

Does Adding Indexes speed up String Wildcard % searches?

We are conducting a wildcard search on a database table with column string. Does creating a non-clustered index on columns help with wildcard searches? Will this improve performance?
CREATE TABLE [dbo].[Product](
[ProductId] [int] NOT NULL,
[ProductName] [varchar](250) NOT NULL,
[ModifiedDate] [datetime] NOT NULL,
...
CONSTRAINT [PK_ProductId] PRIMARY KEY CLUSTERED
(
[ProductId] ASC
)
)
Proposed Index:
CREATE NONCLUSTERED INDEX [IX_Product_ProductName] ON [dbo].[Product] [ProductName])
for this query
select * from dbo.Product where ProductName like '%furniture%'
Currently using Microsoft SQL Server 2019.
Creating a normal index will not help(*), but a full-text index will, though you would have to change your query to something like this:
select * from dbo.Product where ProductName CONTAINS 'furniture'
(* -- well, it can be slightly helpful, in that it can reduce a scan over every row and column in your table into a scan over merely every row and only the relevant columns. However, it will not achieve the orders of magnitude performance boost that we normally expect from indexes that turn scans into single seeks.)
For a double ended wildcard search as shown, an index cannot help you by restricting the rows SQL Server has to look at - a full table scan will be carried out. But it can help with the amount of data that has to be retrieved from disk.
Because in ProductName like '%furniture%', ProductName could start or end with any string, so no index can reduce the rows that have to be inspected.
However if a row in your Product table is 1,000 characters and you have 10,000 rows, you have to load that much data. But if you have an index on ProductName, and ProductName is only 50 characters, then you only have to load 10,000 * 50 rather than 10,000 * 1000.
Note: If the query was a single ended wildcard search with % at end of 'furniture%', then the proposed index would certainly help.
First you can use FTS to search words into sentences even partially (beginning by).
For those ending by or for those containing you can use a rotative indexing technic:
CREATE TABLE T_WRD
(WRD_ID BIGINT IDENTITY PRIMARY KEY,
WRD_WORD VARCHAR(64) COLLATE Latin1_General_100_BIN NOT NULL UNIQUE,
WRD_DROW AS REVERSE(WRD_WORD) PERSISTED NOT NULL UNIQUE,
WRD_WORD2 VARCHAR(64) COLLATE Latin1_General_100_CI_AI NOT NULL) ;
GO
CREATE TABLE T_WORD_ROTATE_STRING_WRS
(WRD_ID BIGINT NOT NULL REFERENCES T_WRD (WRD_ID),
WRS_ROTATE SMALLINT NOT NULL,
WRD_ID_PART BIGINT NOT NULL REFERENCES T_WRD (WRD_ID),
PRIMARY KEY (WRD_ID, WRS_ROTATE));
GO
CREATE OR ALTER TRIGGER E_I_WRD
ON T_WRD
FOR INSERT
AS
SET NOCOUNT ON;
-- splitting words
WITH R AS
(
SELECT WRD_ID, TRIM(WRD_WORD) AS WRD_WORD, 0 AS ROTATE
FROM INSERTED
UNION ALL
SELECT WRD_ID, RIGHT(WRD_WORD, LEN(WRD_WORD) -1), ROTATE + 1
FROM R
WHERE LEN(WRD_WORD) > 1
)
SELECT *
INTO #WRD
FROM R;
-- inserting missing words
INSERT INTO T_WRD (WRD_WORD, WRD_WORD2)
SELECT WRD_WORD, LOWER(WRD_WORD) COLLATE SQL_Latin1_General_CP1251_CI_AS
FROM #WRD
WHERE WRD_WORD NOT IN (SELECT WRD_WORD
FROM T_WRD);
-- inserting cross reference words
INSERT INTO T_WORD_ROTATE_STRING_WRS
SELECT M.WRD_ID, ROTATE, D.WRD_ID
FROM #WRD AS M
JOIN T_WRD AS D
ON M.WRD_WORD = D.WRD_WORD
WHERE NOT EXISTS(SELECT 1/0
FROM T_WORD_ROTATE_STRING_WRS AS S
WHERE S.WRD_ID = M.WRD_ID
AND S.WRS_ROTATE = ROTATE);
GO
Then now you can insert into the first table all the words you want from your sentences and finding it by ending of partially in querying those two tables...
As an example, word:
WITH
T AS (SELECT 'électricité' AS W)
INSERT INTO T_WRD
SELECT W, LOWER(CAST(W AS VARCHAR(64)) COLLATE SQL_Latin1_General_CP1251_CI_AS) AS W2
FROM T;
You can now use :
SELECT * FROM T_WRD;
SELECT * FROM T_WORD_ROTATE_STRING_WRS;
To find those partial words
It depends on the optimizer. Like usually requires a full table scan. if the optimizer can scan an index for matches than it will do an index scan which is faster than a full table scan.
if the optimizer does not select an index scan you can force it to use an index. You must measure performance times to determine if using an index scan decreases search time
Use with (index(index_name)) to force an index scan e.g.
select * from t1 with (index(t1i1)) where v1 like '456%'
SQL Server Index - Any improvement for LIKE queries?
If you use %search% pattern, the optimizer will always perform a full table scan.
Another technique for speeding up searches is to use substrings and exact match searches.
Yes, the part before the first % is matched against the index. Of course however, if your pattern starts with %, then a full scan will be performed instead.

SQL Server : query apply in where clause with IS NOT Null on Column that contains Json Object taking more time

I have a table in a SQL Server database that columns contain JSON object and that column I iterating through where clause condition with IN NOT NULL, by using openJson JSON_Value and JSON_Query function.The query is running successfully but it taking more time to response output.only in 4 rows taking 7sec.
Then what about if table having 1000 of rows.
Table looks lie this:
Here is the query on table that's I'm using:
SELECT TOP (1000)
[Id], JSON_Value(objectJson,'$.Details.Name.Value') AS objectValue
FROM
[geodb].[dbo].[userDetails]
WHERE
JSON_QUERY(jsonData,'$."1bf1548c-3703-88de-108e-bf7c4578c912"') IS NOT NULL
So, how to optimize above query so that it takes less time?
I would suggest altering the table:
ALTER TABLE dbo.Table
ADD Value AS JSON_VALUE(JsonData, '$.Details.Name.Value');
then creating a non clustered index on value column
CREATE NONCLUSTERED INDEX IX_ParsedValue ON dbo.Table (Value)
This will speed up the query.

Sql Server 2008 "Contains" search searching for numeric value returns all records with a different number of the same length?

I have a search where users can enter any value, sometimes these are legitimately just numeric.
When searching for
Select * FROM Updates WHERE contains(Remarks, '"10010234331"')
it will return unrelated results that have numbers in of the same length, ie one match for the above is
"PO input differently on orders, refs are:
1001024894
10010248940"
As you can see, the search is not a substring of either of these. Any ideas how to tell it to not just guess?
Right.
As unbelievable as this sounds, it turns out that if the full-text index "language for word-breaker" is set to anything other than "English", the full-text index will only index the first 5 numbers of a number string.
This means that the above is returning as a match because they both start "10010".
"French, "German", "Hebrew", even "Neutral" was returning incorrect results, only "English" returns only matches for the whole string.
create table wtFTI( taskid int not null , remarks text, constraint [PK__wtFTI] primary key(taskid))
insert into wtfti
values(3513792, 'Remarks: 1001019658 was cancelled 26/08')
GO
CREATE FULLTEXT CATALOG [TaskRemarks]WITH ACCENT_SENSITIVITY = OFF
GO
CREATE FULLTEXT INDEX ON [dbo].[wtFTI] KEY INDEX [PK__wtFTI] ON ([TaskRemarks]) WITH (CHANGE_TRACKING = AUTO, STOPLIST = SYSTEM)
GO
ALTER FULLTEXT INDEX ON [dbo].[wtFTI] ADD ([remarks]LANGUAGE 'French')
GO
ALTER FULLTEXT INDEX ON [dbo].[wtFTI] ENABLE
GO
Select * FROM [wtFTI] WHERE contains(Remarks, '"1001019000"')
ALTER FULLTEXT INDEX ON [dbo].[wtFTI] DROP ([remarks])
GO
ALTER FULLTEXT INDEX ON [dbo].[wtFTI] ADD ([remarks] LANGUAGE 'English')
GO
Select * FROM [wtFTI] WHERE contains(Remarks, '"1001019000"')

Why Postgresql searches Text index faster than Int index?

CREATE TABLE index_test
(
id int PRIMARY KEY NOT NULL,
text varchar(2048) NOT NULL,
value int NOT NULL
);
CREATE INDEX idx_index_value ON index_test ( value );
CREATE INDEX idx_index_value_and_text ON index_test ( value, text );
CREATE INDEX idx_index_text_and_value ON index_test ( text, value );
CREATE INDEX idx_index_text ON index_test ( text );
The table is populated with 10000 random rows, 'value' column has integers from 0 to 100, 'text' column has random 128 bit md5 hash. Sorry for using bad column names.
My searches are:
select * from index_test r where r.value=56;
select * from index_test r where r.value=56 and r.text='dfs';
select * from index_test r where r.text='sdf';
Anytime I make some search...
if only indexes on 'text' and/or 'value' columns are presented
if combined ('text' and 'value' together) indexes are presented
... so, anytime I see the following picture:
The search for integer column 'value' is
slower
is combined from 2 searches: *Bitmap Heap Scan on index_test* and *Bitmap Index Scan on idx_index_value*
The search for varchar column 'text' is
faster
always using an index scan
Why searching for String is easier than searching for Integer?
Why the the search plans differ in that way?
Is there any similar situations when this effect can be reproduced and can be helpful for developers?
As the text is a hash, unique by definition, there will be one only row in the 10k rows of the table matching that text.
The 56 value will exist about 100 times inside the 10k rows and it will be scattered all over the table. So the planner goes first to the index and find the pages where those rows are. Then it visits each of those scattered pages to retrieve the rows.

Index View Index Creation Failing

I'm trying to create an index on a view and it keeps failing, I'm pretty sure its b/c I'm using an alias for the column. Not sure how or if I can do it this way. Below is a simplified scenario.
CREATE VIEW v_contracts WITH SCHEMABINDING
AS
SELECT
t1.contractid as 'Contract.ContractID'
t2.name as 'Customer.Name'
FROM contract t1
JOIN customer t2
ON t1.contractid = t2.contractid
GO
CREATE UNIQUE CLUSTERED INDEX v_contracts_idx ON v_contracts(t1.contractid)
GO
---------------------------
Incorrect syntax near '.'.
CREATE UNIQUE CLUSTERED INDEX v_contracts_idx ON v_contracts(contractid)
GO
---------------------------
Column name 'contractid' does not exist in the target table or view.
CREATE UNIQUE CLUSTERED INDEX v_contracts_idx ON v_contracts(Contract.ContractID)
GO
---------------------------
Incorrect syntax near '.'.
Anyone know how to create an indexed view using aliased columns please let me know.
try using brackets around the column name because the name is not a valid column name
CREATE UNIQUE CLUSTERED INDEX v_contracts_idx
ON v_contracts([Contract.ContractID])
GO
Also indexed views require 5 or so SET options to be on, more info here: http://msdn.microsoft.com/en-us/library/ms191432.aspx
How about a comma between the two columns???
SELECT
t1.contractid as 'Contract.ContractID' -- <=== comma missing here
t2.name as 'Customer.Name'
And I probably wouldn't really use "Contract.ContractID" as my alias..... the dotted notation has special meaning in SQL Server (database.schema.object) - so I would avoid anything that could cause trouble there.....
CREATE VIEW v_contracts WITH SCHEMABINDING
AS
SELECT
t1.contractid as 'ContractID' , -- comma here at the end!!
t2.name as 'CustomerName'
FROM contract t1
JOIN customer t2 ON t1.contractid = t2.contractid
GO
CREATE UNIQUE CLUSTERED INDEX v_contracts_idx ON v_contracts(ContractID)
GO
Why are you aliasing the tables if you are simply going to re-alias the columns back to the original?? Just do
CREATE VIEW v_contracts WITH SCHEMABINDING
AS
SELECT
Contract.ContractID,
Customer.Name
FROM contract
JOIN customer
ON contract.contractid = customer.contractid
GO
And yes, you were missing a comma.