Programing

select *를 사용하지 않는 이유는 무엇입니까?

crosscheck 2020. 6. 26. 08:14
반응형

select *를 사용하지 않는 이유는 무엇입니까?


나는 많은 사람들이 선택 쿼리에서 원하는 각 열의 이름을 구체적으로 지정해야한다고 주장하는 것을 보았습니다.

어쨌든 모든 열을 사용한다고 가정하면 왜 사용하지 SELECT *않습니까?

질문 * SQL 쿼리-보기에서 * 선택 또는보기에서 col1, col2,… colN 선택 *을 고려하더라도 약간 다른 관점에서 문제에 접근 할 때 이것이 정확히 중복되지는 않습니다.

우리의 원칙 중 하나는 시간이 지나기 전에 최적화하지 않는 것입니다. 이를 염두에두고 리소스 문제로 입증되거나 스키마가 거의 설정 될 때까지 사용 SELECT *하는 것이 선호되는 방법 인 것처럼 보입니다 . 우리가 알고 있듯이 개발이 완전히 완료 될 때까지 발생하지 않습니다.

즉, 사용하지 않는 가장 중요한 문제가 SELECT *있습니까?


조기에 최적화하지 않는다는 인용의 본질은 간단하고 간단한 코드를 찾은 다음 프로파일 러를 사용하여 핫스팟을 지적하는 것입니다. 그러면 효율적으로 최적화 할 수 있습니다.

select *를 사용하면 프로파일 링이 불가능하므로 명확하고 간단한 코드를 작성하지 않으므로 인용의 정신에 위배됩니다. select *안티 패턴입니다.


따라서 열을 선택하는 것은 조기 최적화가 아닙니다. 내 머리 꼭대기에서 몇 가지 ....

  1. SQL 문에 열을 지정하면 해당 열이 테이블에서 제거되고 쿼리가 실행되면 SQL 실행 엔진이 오류를 발생시킵니다.
  2. 해당 열이 사용되는 코드를 더 쉽게 스캔 할 수 있습니다.
  3. 최소한의 정보를 다시 가져 오려면 항상 쿼리를 작성해야합니다.
  4. 서수 열 액세스를 사용하는 경우 다른 사람들이 언급했듯이 select *를 사용해서는 안됩니다.
  5. SQL 문이 테이블을 조인하는 경우 select *는 조인에있는 모든 테이블의 모든 열을 제공합니다.

그 결과는 select *...

  1. 응용 프로그램에서 사용하는 열이 불투명합니다
  2. DBA 및 해당 쿼리 프로파일 러가 애플리케이션의 성능 저하를 도울 수 없음
  3. 변경 사항이 발생하면 코드가 더 부서지기 쉽습니다.
  4. 데이터베이스와 네트워크가 너무 많은 데이터를 가져 오기 때문에 어려움을 겪고 있습니다 (I / O)
  5. 데이터베이스 엔진 최적화는 최소 (논리적)에 관계없이 모든 데이터를 다시 가져 오므로 최소화됩니다.

올바른 SQL을 작성하는 것은 작성하는 것만 큼 쉽습니다 Select *. 따라서 실제 게으른 사람은 코드를 다시 방문하지 않고 코드를 다시 작성하고 싶지 않았기 때문에 올바른 SQL을 작성합니다. 그들은 모든 코드 비트에 대해 DBA에 설명하고 싶지 않습니다. 그들은 왜 응용 프로그램이 개처럼 실행되는지 고객에게 설명하고 싶지 않습니다.


코드가 특정 순서의 열에 의존하는 경우 테이블이 변경되면 코드가 중단됩니다. 또한 *를 선택할 때 특히 테이블에 이진 필드가있는 경우 테이블에서 너무 많은 페치가 발생할 수 있습니다.

지금 모든 열을 사용한다고해서 다른 사람이 테이블에 추가 열을 추가하지 않는다는 의미는 아닙니다.

또한 테이블에 대한 메타 데이터를 가져 와서 *에있는 열을 알아야하기 때문에 계획 실행 캐싱에 오버 헤드를 추가합니다.


주요한 이유 중 하나는 테이블에서 열을 추가 / 제거 할 경우 SELECT * 호출을 수행하는 모든 쿼리 / 프로 시저가 예상보다 많은 데이터 열을 가져 오는 것입니다.


  1. 로터리 방식으로 가능한 한 엄격한 타이핑을 사용하는 것에 대한 모듈화 규칙을 어 기고 있습니다. 명시 적으로 거의 보편적으로 좋습니다.

  2. 이제 테이블의 모든 열이 필요하더라도 나중에 쿼리를 실행할 때마다 풀다운되어 성능이 저하 될 수 있습니다. 성능이 저하되므로

    • 와이어를 통해 더 많은 데이터를 가져오고 있습니다.
    • 테이블 자체에서 조회를 수행하는 대신 인덱스에서 데이터를 바로 가져 오는 옵티마이 저의 기능 (인덱스의 일부인 열에 대한 쿼리의 경우)을 무시할 수 있기 때문입니다.

사용할 때 선택 *

QUERY를 기록 할 당시 존재했던 테이블의 모든 열이 필요하지 않고, 테이블의 모든 열을 명시 적으로 필요로하는 경우. 예를 들어, 테이블의 전체 내용을 표시하는 데 필요한 DB 관리 앱을 작성하는 경우 (어떤 일이 있었 든) 해당 방식을 사용할 수 있습니다.


몇 가지 이유가 있습니다.

  1. 데이터베이스의 열 수가 변경되고 응용 프로그램에 특정 수가있을 것으로 예상되는 경우 ...
  2. 데이터베이스의 열 순서가 변경되고 응용 프로그램에서 특정 순서를 기대하는 경우 ...
  3. 메모리 오버 헤드. 8 개의 불필요한 INTEGER 열은 32 바이트의 낭비 된 메모리를 추가합니다. 그것은별로 들리지 않지만, 이것은 각 쿼리에 대한 것이고 INTEGER는 작은 열 유형 중 하나입니다 ... 추가 열은 VARCHAR 또는 TEXT 열일 가능성이 높으므로 더 빨리 추가됩니다.
  4. 네트워크 오버 헤드. 메모리 오버 헤드와 관련하여 : 30,000 개의 쿼리를 발행하고 8 개의 불필요한 INTEGER 열이 있으면 960kB의 대역폭을 낭비했습니다. VARCHAR 및 TEXT 컬럼이 상당히 클 수 있습니다.

참고 : 위의 예제에서는 고정 크기가 4 바이트이므로 INTEGER를 선택했습니다.


응용 프로그램에서 SELECT *를 사용하여 데이터를 가져오고 데이터베이스의 테이블 구조가 변경되면 (예 : 열 제거) 누락 된 필드를 참조하는 모든 위치에서 응용 프로그램이 실패합니다. 대신 쿼리에 모든 열을 포함 시키면 응용 프로그램이 처음에 데이터를 얻는 위치 (바람직하게)에서 깨져서 수정이 쉬워집니다.

즉, SELECT *가 바람직한 여러 가지 상황이 있습니다. 하나는 항상 전체 테이블을 다른 데이터베이스 (예 : SQL Server에서 DB2로)로 복제해야하는 상황입니다. 다른 하나는 일반적으로 테이블을 표시하도록 작성된 응용 프로그램입니다 (즉, 특정 테이블에 대한 지식이 없음).


실제로 select *SQL Server 2005의 뷰에서 사용할 때 이상한 동작을 발견했습니다 .

다음 쿼리를 실행하면 무슨 뜻인지 알 수 있습니다.

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[starTest]') AND type in (N'U'))
DROP TABLE [dbo].[starTest]
CREATE TABLE [dbo].[starTest](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [A] [varchar](50) NULL,
    [B] [varchar](50) NULL,
    [C] [varchar](50) NULL
) ON [PRIMARY]

GO

insert into dbo.starTest
select 'a1','b1','c1'
union all select 'a2','b2','c2'
union all select 'a3','b3','c3'

go
IF  EXISTS (SELECT * FROM sys.views WHERE object_id = OBJECT_ID(N'[dbo].[vStartest]'))
DROP VIEW [dbo].[vStartest]
go
create view dbo.vStartest as
select * from dbo.starTest
go

go
IF  EXISTS (SELECT * FROM sys.views WHERE object_id = OBJECT_ID(N'[dbo].[vExplicittest]'))
DROP VIEW [dbo].[vExplicittest]
go
create view dbo.[vExplicittest] as
select a,b,c from dbo.starTest
go


select a,b,c from dbo.vStartest
select a,b,c from dbo.vExplicitTest

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[starTest]') AND type in (N'U'))
DROP TABLE [dbo].[starTest]
CREATE TABLE [dbo].[starTest](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [A] [varchar](50) NULL,
    [B] [varchar](50) NULL,
    [D] [varchar](50) NULL,
    [C] [varchar](50) NULL
) ON [PRIMARY]

GO

insert into dbo.starTest
select 'a1','b1','d1','c1'
union all select 'a2','b2','d2','c2'
union all select 'a3','b3','d3','c3'

select a,b,c from dbo.vStartest
select a,b,c from dbo.vExplicittest

마지막 2 개의 select 문의 결과를 비교하십시오. 나는 당신이 보게 될 것은 이름 대신 인덱스로 열을 참조 하는 Select * 의 결과라고 생각합니다 .

뷰를 다시 빌드하면 다시 정상적으로 작동합니다.

편집하다

SQL Server 2005의 흥미로운 동작 인“테이블에서 선택 *”과“테이블에서 colA, colB 등 선택”과 같은 별도의 질문을 추가했습니다 .


두 테이블을 조인하고 두 번째 테이블의 열 A를 사용할 수 있습니다. 나중에 A 열을 이름이 같지만 의미가 다른 첫 번째 테이블에 추가하면 첫 번째 테이블에서 값을 얻을 수있을 것입니다. 선택할 열을 명시 적으로 지정하면 발생하지 않습니다.

Of course specifying the columns also sometimes causes bugs if you forget to add the new columns to every select clause. If the new column is not needed every time the query is executed, it may take some time before the bug gets noticed.


I understand where you're going regarding premature optimization, but that really only goes to a point. The intent is to avoid unnecessary optimization in the beginning. Are your tables unindexed? Would you use nvarchar(4000) to store a zip code?

As others have pointed out, there are other positives to specifying each column you intend to use in the query (such as maintainability).


When you're specifying columns, you're also tying yourself into a specific set of columns and making yourself less flexible, making Feuerstein roll over in, well, whereever he is. Just a thought.


SELECT * is not always evil. In my opinion, at least. I use it quite often for dynamic queries returning a whole table, plus some computed fields.

For instance, I want to compute geographical geometries from a "normal" table, that is a table without any geometry field, but with fields containing coordinates. I use postgresql, and its spatial extension postgis. But the principle applies for many other cases.

An example:

  • a table of places, with coordinates stored in fields labeled x, y, z:

    CREATE TABLE places (place_id integer, x numeric(10, 3), y numeric(10, 3), z numeric(10, 3), description varchar);

  • let's feed it with a few example values:

    INSERT INTO places (place_id, x, y, z, description) VALUES
    (1, 2.295, 48.863, 64, 'Paris, Place de l\'Étoile'),
    (2, 2.945, 48.858, 40, 'Paris, Tour Eiffel'),
    (3, 0.373, 43.958, 90, 'Condom, Cathédrale St-Pierre');

  • I want to be able to map the contents of this table, using some GIS client. The normal way is to add a geometry field to the table, and build the geometry, based on the coordinates. But I would prefer to get a dynamic query: this way, when I change coordinates (corrections, more accuracy, etc.), the objects mapped actually move, dynamically. So here is the query with the SELECT *:

    CREATE OR REPLACE VIEW places_points AS
    SELECT *,
    GeomFromewkt('SRID=4326; POINT ('|| x || ' ' || y || ' ' || z || ')')
    FROM places;

    Refer to postgis, for GeomFromewkt() function use.

  • Here is the result:

    SELECT * FROM places_points;

 place_id |   x   |   y    |   z    |         description          |                            geomfromewkt                            
----------+-------+--------+--------+------------------------------+--------------------------------------------------------------------  
        1 | 2.295 | 48.863 | 64.000 | Paris, Place de l'Étoile     | 01010000A0E61000005C8FC2F5285C02405839B4C8766E48400000000000005040  
        2 | 2.945 | 48.858 | 40.000 | Paris, Tour Eiffel           | 01010000A0E61000008FC2F5285C8F0740E7FBA9F1D26D48400000000000004440
        3 | 0.373 | 43.958 | 90.000 | Condom, Cathédrale St-Pierre | 01010000A0E6100000AC1C5A643BDFD73FB4C876BE9FFA45400000000000805640
(3 lignes)

The rightmost column can now be used by any GIS program to properly map the points.

  • If, in the future, some fields get added to the table: no worries, I just have to run again the same VIEW definition.

I wish the definition of the VIEW could be kept "as is", with the *, but hélas it is not the case: this is how it is internally stored by postgresql:

SELECT places.place_id, places.x, places.y, places.z, places.description, geomfromewkt(((((('SRID=4326; POINT ('::text || places.x) || ' '::text) || places.y) || ' '::text) || places.z) || ')'::text) AS geomfromewkt FROM places;


Even if you use every column but address the row array by numeric index you will have problems if you add another row later on.

So basically it is a question of maintainability! If you don't use the * selector you will not have to worry about your queries.


Selecting only the columns you need keeps the dataset in memory smaller and therefor keeps your application faster.

Also, a lot of tools (e.g. stored procedures) cache query execution plans too. If you later add or remove a column (particularly easy if you're selecting off a view), the tool will often error when it doesn't get back results that it expects.


It makes your code more ambiguous and more difficult to maintain; because you're adding extra unused data to the domain, and it's not clear which you've intended and which not. (It also suggests that you might not know, or care.)


To answer you question directly: Do not use "SELECT *" when it makes your code more fragle to changes to the underlying tables. Your code should break only when a change is made to the table that directly affects requirments of your program.

Your application should take advantage of the abstraction layer that Relational access provides.


I don't use SELECT * simply because it is nice to see and know what fields I am retrieving.


Generally bad to use 'select *' inside of views because you will be forced to recompile the view in the event of a table column change. Changing the underlying table columns of a view you will get an error for non-existant columns until you go back and recompile.


It's ok when you're doing exists(select * ...) since it never gets expanded. Otherwise it's really only useful when exploring tables with temporary select statments or if you had a CTE defined above and you want every column without typing them all out again.


Just to add one thing that no one else has mentioned. Select * returns all the columns, someone may add a column later that you don't necessarily want the users to be able to see such as who last updated the data or a timestamp or notes that only managers should see not all users, etc.

Further, when adding a column, the impact on existing code should be reviewed and considered to see if changes are needed based on what information is stored in the column. By using select *, that review will often be skipped because the developer will assume that nothing will break. And in fact nothing may explicitly appear to break but queries may now start returning the wrong thing. Just because nothing explicitly breaks, doesn't mean that there should not have been changes to the queries.


because "select * " will waste memory when you don't need all the fields.But for sql server, their performence are the same.

참고URL : https://stackoverflow.com/questions/321299/what-is-the-reason-not-to-use-select

반응형